POL Price: $0.398426 (+2.16%)
Gas: 31 GWei
 

Overview

POL Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 POL

POL Value

$0.00

Sponsored

Transaction Hash
Method
Block
From
To
0x60806040270499292022-04-12 13:50:17891 days ago1649771417IN
 Create: RetireMossCarbon
0 POL0.1354806557.79856958

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RetireMossCarbon

Compiler Version
v0.8.11+commit.d7f03943

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : RetireMossCarbon.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

import "./interfaces/IUniswapV2Pair.sol";
import "./interfaces/IUniswapV2Router02.sol";
import "./interfaces/IStaking.sol";
import "./interfaces/IStakingHelper.sol";
import "./interfaces/IwsKLIMA.sol";
import "./interfaces/IKlimaCarbonRetirements.sol";
import "./interfaces/ICarbonChain.sol";
import "./interfaces/IKlimaRetirementAggregator.sol";

contract RetireMossCarbon is
    Initializable,
    ContextUpgradeable,
    OwnableUpgradeable
{
    using SafeERC20Upgradeable for IERC20Upgradeable;

    function initialize() public initializer {
        __Ownable_init();
        __Context_init();
    }

    /** === State Variables and Mappings === */

    /// @notice feeAmount represents the fee to be bonded for KLIMA. 0.1% increments. 10 = 1%

    uint256 public feeAmount;
    address public carbonChain;
    address public masterAggregator;
    mapping(address => bool) public isPoolToken;
    mapping(address => address) public poolRouter;

    /** === Event Setup === */

    event MossRetired(
        address indexed retiringAddress,
        address indexed beneficiaryAddress,
        string beneficiaryString,
        string retirementMessage,
        address indexed carbonPool,
        uint256 retiredAmount
    );
    event PoolAdded(address indexed carbonPool, address indexed poolRouter);
    event PoolRemoved(address indexed carbonPool);
    event PoolRouterChanged(
        address indexed carbonPool,
        address indexed oldRouter,
        address indexed newRouter
    );
    event FeeUpdated(uint256 oldFee, uint256 newFee);
    event CarbonChainUpdated(
        address indexed oldAddress,
        address indexed newAddress
    );
    event MasterAggregatorUpdated(
        address indexed oldAddress,
        address indexed newAddress
    );

    /**
     * @notice This function transfers source tokens if needed, swaps to the Moss
     * pool token, and then retires via their CarbonChain interface. Needed source
     * token amount is expected to be held by the caller to use.
     *
     * @param _sourceToken The contract address of the token being supplied.
     * @param _poolToken The contract address of the pool token being retired.
     * @param _amount The amount being supplied. Expressed in either the total
     *          carbon to offset or the total source to spend. See _amountInCarbon.
     * @param _amountInCarbon Bool indicating if _amount is in carbon or source.
     * @param _beneficiaryAddress Address of the beneficiary of the retirement.
     * @param _beneficiaryString String representing the beneficiary. A name perhaps.
     * @param _retirementMessage Specific message relating to this retirement event.
     * @param _retiree The original sender of the transaction.
     */
    function retireMoss(
        address _sourceToken,
        address _poolToken,
        uint256 _amount,
        bool _amountInCarbon,
        address _beneficiaryAddress,
        string memory _beneficiaryString,
        string memory _retirementMessage,
        address _retiree
    ) public {
        require(isPoolToken[_poolToken], "Not a Moss Carbon Token");

        // Transfer source tokens

        (
            uint256 sourceAmount,
            uint256 totalCarbon,
            uint256 fee
        ) = _transferSourceTokens(
                _sourceToken,
                _poolToken,
                _amount,
                _amountInCarbon
            );

        // Get the pool tokens

        if (_sourceToken != _poolToken) {
            // Swap the source to get pool
            if (_amountInCarbon) {
                // swapTokensForExactTokens
                _swapForExactCarbon(
                    _sourceToken,
                    _poolToken,
                    totalCarbon,
                    sourceAmount,
                    _retiree
                );
            } else {
                // swapExactTokensForTokens
                (_amount, fee) = _swapExactForCarbon(
                    _sourceToken,
                    _poolToken,
                    sourceAmount
                );
            }
        } else if (!_amountInCarbon) {
            // Calculate the fee and adjust if pool token is provided with false bool
            fee = (_amount * feeAmount) / 1000;
            _amount = _amount - fee;
        }

        // At this point _amount = the amount of carbon to retire

        // Retire the tokens
        _retireCarbon(
            _amount,
            _beneficiaryAddress,
            _beneficiaryString,
            _retirementMessage,
            _poolToken
        );

        // Send the fee to the treasury
        if (feeAmount > 0) {
            IERC20Upgradeable(_poolToken).safeTransfer(
                IKlimaRetirementAggregator(masterAggregator).treasury(),
                fee
            );
        }
    }

    /**
     * @notice Retires the MCO2 tokens on Polygon where they will be bridged back to L1.
     * Emits a retirement event and updates the KlimaCarbonRetirements contract with
     * retirement details and amounts.
     * @param _totalAmount Total pool tokens being retired. Expected uint with 18 decimals.
     * @param _beneficiaryAddress Address of the beneficiary if different than sender. Value is set to _msgSender() if null is sent.
     * @param _beneficiaryString String that can be used to describe the beneficiary
     * @param _retirementMessage String for specific retirement message if needed.
     * @param _poolToken Address of pool token being used to retire.
     */
    function _retireCarbon(
        uint256 _totalAmount,
        address _beneficiaryAddress,
        string memory _beneficiaryString,
        string memory _retirementMessage,
        address _poolToken
    ) internal {
        // Assign default event values
        if (_beneficiaryAddress == address(0)) {
            _beneficiaryAddress = _msgSender();
        }

        address retirementStorage = IKlimaRetirementAggregator(masterAggregator)
            .klimaRetirementStorage();

        // Retire MCO2
        IERC20Upgradeable(_poolToken).safeIncreaseAllowance(
            carbonChain,
            _totalAmount
        );
        ICarbonChain(carbonChain).offsetCarbon(
            _totalAmount,
            _retirementMessage,
            _beneficiaryString
        );
        IKlimaCarbonRetirements(retirementStorage).carbonRetired(
            _beneficiaryAddress,
            _poolToken,
            _totalAmount,
            _beneficiaryString,
            _retirementMessage
        );
        emit MossRetired(
            _msgSender(),
            _beneficiaryAddress,
            _beneficiaryString,
            _retirementMessage,
            _poolToken,
            _totalAmount
        );
    }

    /**
     * @notice Transfers the needed source tokens from the caller to perform any needed
     * swaps and then retire the tokens.
     * @param _sourceToken The contract address of the token being supplied.
     * @param _poolToken The contract address of the pool token being retired.
     * @param _amount The amount being supplied. Expressed in either the total
     *          carbon to offset or the total source to spend. See _amountInCarbon.
     * @param _amountInCarbon Bool indicating if _amount is in carbon or source.
     */
    function _transferSourceTokens(
        address _sourceToken,
        address _poolToken,
        uint256 _amount,
        bool _amountInCarbon
    )
        internal
        returns (
            uint256,
            uint256,
            uint256
        )
    {
        address sKLIMA = IKlimaRetirementAggregator(masterAggregator).sKLIMA();
        address wsKLIMA = IKlimaRetirementAggregator(masterAggregator)
            .wsKLIMA();

        uint256 fee;
        uint256 sourceAmount;

        // If submitting the amount in carbon, add fee to transfer amount.
        if (_amountInCarbon) {
            (sourceAmount, fee) = getNeededBuyAmount(
                _sourceToken,
                _poolToken,
                _amount,
                false
            );
        } else {
            sourceAmount = _amount;
        }

        if (_sourceToken == sKLIMA || _sourceToken == wsKLIMA) {
            sourceAmount = _stakedToUnstaked(_sourceToken, sourceAmount);
        } else {
            IERC20Upgradeable(_sourceToken).safeTransferFrom(
                _msgSender(),
                address(this),
                sourceAmount
            );
        }

        return (sourceAmount, _amount + fee, fee);
    }

    /**
     * @notice Unwraps/unstakes any KLIMA needed to regular KLIMA.
     * @param _klimaType Address of the KLIMA type being used.
     * @param _amountIn Amount of total KLIMA needed.
     * @return Returns the total number of KLIMA after unwrapping/unstaking.
     */
    function _stakedToUnstaked(address _klimaType, uint256 _amountIn)
        internal
        returns (uint256)
    {
        uint256 unwrappedKLIMA = _amountIn;

        // Get token addresses from master
        address sKLIMA = IKlimaRetirementAggregator(masterAggregator).sKLIMA();
        address wsKLIMA = IKlimaRetirementAggregator(masterAggregator)
            .wsKLIMA();
        address staking = IKlimaRetirementAggregator(masterAggregator)
            .staking();

        if (_klimaType == wsKLIMA) {
            // Get wsKLIMA needed, transfer and unwrap, unstake to KLIMA
            uint256 wsKLIMANeeded = IwsKLIMA(wsKLIMA).sKLIMATowKLIMA(_amountIn);

            IERC20Upgradeable(wsKLIMA).safeTransferFrom(
                _msgSender(),
                address(this),
                wsKLIMANeeded
            );
            IERC20Upgradeable(wsKLIMA).safeIncreaseAllowance(
                wsKLIMA,
                wsKLIMANeeded
            );
            unwrappedKLIMA = IwsKLIMA(wsKLIMA).unwrap(wsKLIMANeeded);
        }

        // If using sKLIMA, transfer in and unstake
        if (_klimaType == sKLIMA) {
            IERC20Upgradeable(sKLIMA).safeTransferFrom(
                _msgSender(),
                address(this),
                unwrappedKLIMA
            );
        }
        IERC20Upgradeable(sKLIMA).safeIncreaseAllowance(
            staking,
            unwrappedKLIMA
        );
        IStaking(staking).unstake(unwrappedKLIMA, false);

        return unwrappedKLIMA;
    }

    /**
     * @notice Call the UniswapV2 routers for needed amounts on token being retired.
     * Also calculates and returns any fee needed in the pool token total.
     * @param _sourceToken Address of token being used to purchase the pool token.
     * @param _poolToken Address of pool token being used.
     * @param _poolAmount Amount of tokens being retired.
     * @return Tuple of the total pool amount needed, followed by the fee.
     */
    function getNeededBuyAmount(
        address _sourceToken,
        address _poolToken,
        uint256 _poolAmount,
        bool _specificRetire // @dev Added to maintain consistency between all bridges.
    ) public view returns (uint256, uint256) {
        uint256 fee = (_poolAmount * feeAmount) / 1000;
        uint256 totalAmount = _poolAmount + fee;

        if (_sourceToken != _poolToken) {
            address[] memory path = getSwapPath(_sourceToken, _poolToken);

            uint256[] memory amountIn = IUniswapV2Router02(
                poolRouter[_poolToken]
            ).getAmountsIn(totalAmount, path);

            // Account for .1% default AMM slippage.
            totalAmount = (amountIn[0] * 1001) / 1000;
        }

        return (totalAmount, fee);
    }

    /**
     * @notice Creates an array of addresses to use in performing any needed
     * swaps to receive the pool token from the source token.
     *
     * @dev This function will produce an invalid path if the source token
     * does not have a direct USDC LP route on the pool's AMM. The resulting
     * transaction would revert.
     *
     * @param _sourceToken Address of token being used to purchase the pool token.
     * @param _poolToken Address of pool token being used.
     * @return Array of addresses to be used as the path for the swap.
     */
    function getSwapPath(address _sourceToken, address _poolToken)
        public
        view
        returns (address[] memory)
    {
        address[] memory path;

        // Get addresses from master.
        address KLIMA = IKlimaRetirementAggregator(masterAggregator).KLIMA();
        address sKLIMA = IKlimaRetirementAggregator(masterAggregator).sKLIMA();
        address wsKLIMA = IKlimaRetirementAggregator(masterAggregator)
            .wsKLIMA();
        address USDC = IKlimaRetirementAggregator(masterAggregator).USDC();

        // Account for sKLIMA and wsKLIMA source tokens - swapping with KLIMA
        if (_sourceToken == sKLIMA || _sourceToken == wsKLIMA) {
            _sourceToken = KLIMA;
        }

        // If the source is KLIMA or USDC do a direct swap, else route through USDC.
        if (_sourceToken == KLIMA || _sourceToken == USDC) {
            path = new address[](2);
            path[0] = _sourceToken;
            path[1] = _poolToken;
        } else {
            path = new address[](3);
            path[0] = _sourceToken;
            path[1] = USDC;
            path[2] = _poolToken;
        }

        return path;
    }

    /**
     * @notice Swaps the source token for an exact number of carbon tokens, and
     * returns any dust to the initiator.
     *
     * @dev This is only called if the _amountInCarbon bool is set to true.
     *
     * @param _sourceToken Address of token being used to purchase the pool token.
     * @param _poolToken Address of pool token being used.
     * @param _carbonAmount Total carbon needed.
     * @param _amountIn Maximum amount of source tokens.
     * @param _retiree Initiator of the retirement to return any dust.
     */
    function _swapForExactCarbon(
        address _sourceToken,
        address _poolToken,
        uint256 _carbonAmount,
        uint256 _amountIn,
        address _retiree
    ) internal {
        address[] memory path = getSwapPath(_sourceToken, _poolToken);

        IERC20Upgradeable(path[0]).safeIncreaseAllowance(
            poolRouter[_poolToken],
            _amountIn
        );

        uint256[] memory amounts = IUniswapV2Router02(poolRouter[_poolToken])
            .swapTokensForExactTokens(
                _carbonAmount,
                _amountIn,
                path,
                address(this),
                block.timestamp
            );

        _returnTradeDust(amounts, _sourceToken, _amountIn, _retiree);
    }

    /**
     * @notice Swaps an exact number of source tokens for carbon tokens.
     *
     * @dev This is only called if the _amountInCarbon bool is set to false.
     *
     * @param _sourceToken Address of token being used to purchase the pool token.
     * @param _poolToken Address of pool token being used.
     * @param _amountIn Total source tokens to swap.
     * @return Returns the resulting carbon amount to retire and the fee from the
     * results of the swap.
     */
    function _swapExactForCarbon(
        address _sourceToken,
        address _poolToken,
        uint256 _amountIn
    ) internal returns (uint256, uint256) {
        address[] memory path = getSwapPath(_sourceToken, _poolToken);

        uint256[] memory amountsOut = IUniswapV2Router02(poolRouter[_poolToken])
            .getAmountsOut(_amountIn, path);

        uint256 totalCarbon = amountsOut[path.length - 1];

        IERC20Upgradeable(_sourceToken).safeIncreaseAllowance(
            poolRouter[_poolToken],
            _amountIn
        );

        uint256[] memory amounts = IUniswapV2Router02(poolRouter[_poolToken])
            .swapExactTokensForTokens(
                _amountIn,
                (totalCarbon * 995) / 1000,
                path,
                address(this),
                block.timestamp
            );

        totalCarbon = amounts[amounts.length - 1] == 0
            ? amounts[amounts.length - 2]
            : amounts[amounts.length - 1];

        uint256 fee = (totalCarbon * feeAmount) / 1000;

        return (totalCarbon - fee, fee);
    }

    /**
     * @notice Returns any trade dust to the designated address. If sKLIMA or
     * wsKLIMA was provided as a source token, it is re-staked and/or wrapped
     * before transferring back.
     *
     * @param _amounts The amounts resulting from the Uniswap tradeTokensForExactTokens.
     * @param _sourceToken Address of token being used to purchase the pool token.
     * @param _amountIn Total source tokens initially provided.
     * @param _retiree Address where to send the dust.
     */
    function _returnTradeDust(
        uint256[] memory _amounts,
        address _sourceToken,
        uint256 _amountIn,
        address _retiree
    ) internal {
        address KLIMA = IKlimaRetirementAggregator(masterAggregator).KLIMA();
        address sKLIMA = IKlimaRetirementAggregator(masterAggregator).sKLIMA();
        address wsKLIMA = IKlimaRetirementAggregator(masterAggregator)
            .wsKLIMA();
        address stakingHelper = IKlimaRetirementAggregator(masterAggregator)
            .stakingHelper();

        uint256 tradeDust = _amountIn -
            (_amounts[0] == 0 ? _amounts[1] : _amounts[0]);

        if (_sourceToken == sKLIMA || _sourceToken == wsKLIMA) {
            IERC20Upgradeable(KLIMA).safeIncreaseAllowance(
                stakingHelper,
                tradeDust
            );

            IStakingHelper(stakingHelper).stake(tradeDust);

            if (_sourceToken == sKLIMA) {
                IERC20Upgradeable(sKLIMA).safeTransfer(_retiree, tradeDust);
            } else if (_sourceToken == wsKLIMA) {
                IERC20Upgradeable(sKLIMA).safeIncreaseAllowance(
                    wsKLIMA,
                    tradeDust
                );
                uint256 wrappedDust = IwsKLIMA(wsKLIMA).wrap(tradeDust);
                IERC20Upgradeable(wsKLIMA).safeTransfer(_retiree, wrappedDust);
            }
        } else {
            IERC20Upgradeable(_sourceToken).safeTransfer(_retiree, tradeDust);
        }
    }

    /**
        @notice Set the fee for the helper
        @param _amount New fee amount, in .1% increments. 10 = 1%
        @return bool
     */
    function setFeeAmount(uint256 _amount) external onlyOwner returns (bool) {
        uint256 oldFee = feeAmount;
        feeAmount = _amount;

        emit FeeUpdated(oldFee, feeAmount);
        return true;
    }

    /**
        @notice Update the router for an existing pool
        @param _poolToken Pool being updated
        @param _router New router address
        @return bool
     */
    function setPoolRouter(address _poolToken, address _router)
        external
        onlyOwner
        returns (bool)
    {
        require(isPoolToken[_poolToken], "Pool not added");

        address oldRouter = poolRouter[_poolToken];
        poolRouter[_poolToken] = _router;
        emit PoolRouterChanged(_poolToken, oldRouter, poolRouter[_poolToken]);
        return true;
    }

    /**
        @notice Add a new carbon pool to retire with helper contract
        @param _poolToken Pool being added
        @param _router UniswapV2 router to route trades through for non-pool retirements
        @return bool
     */
    function addPool(address _poolToken, address _router)
        external
        onlyOwner
        returns (bool)
    {
        require(!isPoolToken[_poolToken], "Pool already added");
        require(_poolToken != address(0), "Pool cannot be zero address");

        isPoolToken[_poolToken] = true;
        poolRouter[_poolToken] = _router;

        emit PoolAdded(_poolToken, _router);
        return true;
    }

    /**
        @notice Remove a carbon pool to retire with helper contract
        @param _poolToken Pool being removed
        @return bool
     */
    function removePool(address _poolToken) external onlyOwner returns (bool) {
        require(isPoolToken[_poolToken], "Pool not added");

        isPoolToken[_poolToken] = false;

        emit PoolRemoved(_poolToken);
        return true;
    }

    /**
        @notice Allow withdrawal of any tokens sent in error
        @param _token Address of token to transfer
        @param _recipient Address where to send tokens.
     */
    function feeWithdraw(address _token, address _recipient)
        public
        onlyOwner
        returns (bool)
    {
        IERC20Upgradeable(_token).safeTransfer(
            _recipient,
            IERC20Upgradeable(_token).balanceOf(address(this))
        );

        return true;
    }

    /**
        @notice Allow the contract owner to update the Moss CarbonChain Proxy address used.
        @param _newAddress New address for contract needing to be updated.
        @return bool
     */
    function setCarbonChain(address _newAddress)
        external
        onlyOwner
        returns (bool)
    {
        address oldAddress = carbonChain;
        carbonChain = _newAddress;

        emit CarbonChainUpdated(oldAddress, _newAddress);

        return true;
    }

    /**
        @notice Allow the contract owner to update the master aggregator proxy address used.
        @param _newAddress New address for contract needing to be updated.
        @return bool
     */
    function setMasterAggregator(address _newAddress)
        external
        onlyOwner
        returns (bool)
    {
        address oldAddress = masterAggregator;
        masterAggregator = _newAddress;

        emit MasterAggregatorUpdated(oldAddress, _newAddress);

        return true;
    }
}

File 2 of 16 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.0;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() initializer {}
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        // If the contract is initializing we ignore whether _initialized is set in order to support multiple
        // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
        // contract may have been reentered.
        require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} modifier, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    function _isConstructor() private view returns (bool) {
        return !AddressUpgradeable.isContract(address(this));
    }
}

File 3 of 16 : SafeERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20Upgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20Upgradeable {
    using AddressUpgradeable for address;

    function safeTransfer(
        IERC20Upgradeable token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20Upgradeable token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20Upgradeable token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20Upgradeable token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20Upgradeable token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 4 of 16 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @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 ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 5 of 16 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 6 of 16 : IUniswapV2Pair.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.5.0;

interface IUniswapV2Pair {
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );
    event Transfer(address indexed from, address indexed to, uint256 value);

    function name() external pure returns (string memory);

    function symbol() external pure returns (string memory);

    function decimals() external pure returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256);

    function allowance(address owner, address spender)
        external
        view
        returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function PERMIT_TYPEHASH() external pure returns (bytes32);

    function nonces(address owner) external view returns (uint256);

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(
        address indexed sender,
        uint256 amount0,
        uint256 amount1,
        address indexed to
    );
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint256);

    function factory() external view returns (address);

    function token0() external view returns (address);

    function token1() external view returns (address);

    function getReserves()
        external
        view
        returns (
            uint112 reserve0,
            uint112 reserve1,
            uint32 blockTimestampLast
        );

    function price0CumulativeLast() external view returns (uint256);

    function price1CumulativeLast() external view returns (uint256);

    function kLast() external view returns (uint256);

    function mint(address to) external returns (uint256 liquidity);

    function burn(address to)
        external
        returns (uint256 amount0, uint256 amount1);

    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external;

    function skim(address to) external;

    function sync() external;

    function initialize(address, address) external;
}

File 7 of 16 : IUniswapV2Router02.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.6.2;

import "./IUniswapV2Router01.sol";

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountETH);

    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;
}

File 8 of 16 : IStaking.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IStaking {
    function unstake(uint256 _amount, bool _trigger) external;
}

File 9 of 16 : IStakingHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IStakingHelper {
    function stake(uint256 _amount) external;
}

File 10 of 16 : IwsKLIMA.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IwsKLIMA {
    function wrap(uint256 _amount) external returns (uint256);

    function unwrap(uint256 _amount) external returns (uint256);

    function wKLIMATosKLIMA(uint256 _amount) external view returns (uint256);

    function sKLIMATowKLIMA(uint256 _amount) external view returns (uint256);
}

File 11 of 16 : IKlimaCarbonRetirements.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IKlimaCarbonRetirements {
    function carbonRetired(
        address _retiree,
        address _pool,
        uint256 _amount,
        string calldata _beneficiaryString,
        string calldata _retirementMessage
    ) external;

    function getUnclaimedTotal(address _minter) external view returns (uint256);

    function offsetClaimed(address _minter, uint256 _amount)
        external
        returns (bool);

    function getRetirementIndexInfo(address _retiree, uint256 _index)
        external
        view
        returns (
            address,
            uint256,
            string memory
        );

    function getRetirementPoolInfo(address _retiree, address _pool)
        external
        view
        returns (uint256);

    function getRetirementTotals(address _retiree)
        external
        view
        returns (
            uint256,
            uint256,
            uint256
        );
}

File 12 of 16 : ICarbonChain.sol
//SPDX-License-Identifier: Unlicensed

pragma solidity ^0.8.4;

interface ICarbonChain {
    function offsetCarbon(
        uint256 _carbonTon,
        string calldata _transactionInfo,
        string calldata _onBehalfOf
    ) external;
}

File 13 of 16 : IKlimaRetirementAggregator.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IKlimaRetirementAggregator {
    function KLIMA() external pure returns (address);

    function sKLIMA() external pure returns (address);

    function wsKLIMA() external pure returns (address);

    function USDC() external pure returns (address);

    function staking() external pure returns (address);

    function stakingHelper() external pure returns (address);

    function klimaRetirementStorage() external pure returns (address);

    function treasury() external pure returns (address);
}

File 14 of 16 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 15 of 16 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    /**
     * @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);
}

File 16 of 16 : IUniswapV2Router01.sol
// SPDX-License-Identifier: GPL-3.0

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,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        external
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        );

    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        );

    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETH(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);

    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETHWithPermit(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountToken, uint256 amountETH);

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapETHForExactTokens(
        uint256 amountOut,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) external pure returns (uint256 amountB);

    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut
    ) external pure returns (uint256 amountOut);

    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut
    ) external pure returns (uint256 amountIn);

    function getAmountsOut(uint256 amountIn, address[] calldata path)
        external
        view
        returns (uint256[] memory amounts);

    function getAmountsIn(uint256 amountOut, address[] calldata path)
        external
        view
        returns (uint256[] memory amounts);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"CarbonChainUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"FeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"MasterAggregatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"retiringAddress","type":"address"},{"indexed":true,"internalType":"address","name":"beneficiaryAddress","type":"address"},{"indexed":false,"internalType":"string","name":"beneficiaryString","type":"string"},{"indexed":false,"internalType":"string","name":"retirementMessage","type":"string"},{"indexed":true,"internalType":"address","name":"carbonPool","type":"address"},{"indexed":false,"internalType":"uint256","name":"retiredAmount","type":"uint256"}],"name":"MossRetired","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"carbonPool","type":"address"},{"indexed":true,"internalType":"address","name":"poolRouter","type":"address"}],"name":"PoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"carbonPool","type":"address"}],"name":"PoolRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"carbonPool","type":"address"},{"indexed":true,"internalType":"address","name":"oldRouter","type":"address"},{"indexed":true,"internalType":"address","name":"newRouter","type":"address"}],"name":"PoolRouterChanged","type":"event"},{"inputs":[{"internalType":"address","name":"_poolToken","type":"address"},{"internalType":"address","name":"_router","type":"address"}],"name":"addPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"carbonChain","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"feeWithdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sourceToken","type":"address"},{"internalType":"address","name":"_poolToken","type":"address"},{"internalType":"uint256","name":"_poolAmount","type":"uint256"},{"internalType":"bool","name":"_specificRetire","type":"bool"}],"name":"getNeededBuyAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sourceToken","type":"address"},{"internalType":"address","name":"_poolToken","type":"address"}],"name":"getSwapPath","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isPoolToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterAggregator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"poolRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolToken","type":"address"}],"name":"removePool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sourceToken","type":"address"},{"internalType":"address","name":"_poolToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_amountInCarbon","type":"bool"},{"internalType":"address","name":"_beneficiaryAddress","type":"address"},{"internalType":"string","name":"_beneficiaryString","type":"string"},{"internalType":"string","name":"_retirementMessage","type":"string"},{"internalType":"address","name":"_retiree","type":"address"}],"name":"retireMoss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newAddress","type":"address"}],"name":"setCarbonChain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setFeeAmount","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newAddress","type":"address"}],"name":"setMasterAggregator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_poolToken","type":"address"},{"internalType":"address","name":"_router","type":"address"}],"name":"setPoolRouter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50612972806100206000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c80638129fc1c116100ad578063d31e333011610071578063d31e333014610283578063de260f3714610296578063eb511dd4146102b9578063f2fde38b146102cc578063f772fc8b146102df57600080fd5b80638129fc1c1461020e5780638da5cb5b14610216578063aac2636914610227578063be9e09d614610250578063bf03ed901461027057600080fd5b8063497767c8116100f4578063497767c8146101b457806367d944fd146101c957806369e15404146101dc5780636b392680146101f3578063715018a61461020657600080fd5b8063146d17d6146101265780631824d43914610156578063284fd724146101795780633b7d0946146101a1575b600080fd5b606654610139906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101696101643660046122f0565b6102f2565b604051901515815260200161014d565b61018c610187366004612337565b6103ea565b6040805192835260208301919091520161014d565b6101696101af36600461238a565b610511565b6101c76101c236600461245e565b6105e5565b005b6101696101d736600461238a565b61077b565b6101e560655481565b60405190815260200161014d565b61016961020136600461252b565b6107ff565b6101c7610876565b6101c76108ac565b6033546001600160a01b0316610139565b61013961023536600461238a565b6069602052600090815260409020546001600160a01b031681565b61026361025e3660046122f0565b610975565b60405161014d9190612588565b606754610139906001600160a01b031681565b6101696102913660046122f0565b610d2b565b6101696102a436600461238a565b60686020526000908152604090205460ff1681565b6101696102c73660046122f0565b610de0565b6101c76102da36600461238a565b610f33565b6101696102ed36600461238a565b610fcb565b6033546000906001600160a01b031633146103285760405162461bcd60e51b815260040161031f9061259b565b60405180910390fd5b6001600160a01b03831660009081526068602052604090205460ff166103815760405162461bcd60e51b815260206004820152600e60248201526d141bdbdb081b9bdd08185919195960921b604482015260640161031f565b6001600160a01b0380841660008181526069602052604080822080548786166001600160a01b0319821681179092559151919094169392849290917f0732c0739d0dd4f51f2aab3a4d98921f06be03d94f3f04970bff2285e834d8109190a45060019392505050565b60008060006103e86065548661040091906125e6565b61040a9190612605565b905060006104188287612627565b9050866001600160a01b0316886001600160a01b03161461050557600061043f8989610975565b6001600160a01b03808a166000908152606960205260408082205490516307c0329d60e21b81529394509092911690631f00ca7490610484908690869060040161263f565b600060405180830381865afa1580156104a1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104c99190810190612658565b90506103e8816000815181106104e1576104e16126fe565b60200260200101516103e96104f691906125e6565b6105009190612605565b925050505b97909650945050505050565b6033546000906001600160a01b0316331461053e5760405162461bcd60e51b815260040161031f9061259b565b6001600160a01b03821660009081526068602052604090205460ff166105975760405162461bcd60e51b815260206004820152600e60248201526d141bdbdb081b9bdd08185919195960921b604482015260640161031f565b6001600160a01b038216600081815260686020526040808220805460ff19169055517f4106dfdaa577573db51c0ca93f766dbedfa0758faa2e7f5bcdb7c142be803c3f9190a2506001919050565b6001600160a01b03871660009081526068602052604090205460ff1661064d5760405162461bcd60e51b815260206004820152601760248201527f4e6f742061204d6f737320436172626f6e20546f6b656e000000000000000000604482015260640161031f565b600080600061065e8b8b8b8b61104f565b925092509250896001600160a01b03168b6001600160a01b0316146106aa578715610695576106908b8b8486886111e6565b6106d9565b6106a08b8b856112ed565b90995090506106d9565b876106d9576103e86065548a6106c091906125e6565b6106ca9190612605565b90506106d6818a612714565b98505b6106e6898888888e611546565b6065541561076e57606754604080516361d027b360e01b8152905161076e926001600160a01b0316916361d027b39160048083019260209291908290030181865afa158015610739573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075d919061272b565b6001600160a01b038c169083611715565b5050505050505050505050565b6033546000906001600160a01b031633146107a85760405162461bcd60e51b815260040161031f9061259b565b606780546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f3aaa975adcdc1f75217a6f792ef93a0b0df6b936db83c930741075efbebffe3190600090a350600192915050565b6033546000906001600160a01b0316331461082c5760405162461bcd60e51b815260040161031f9061259b565b606580549083905560408051828152602081018590527f528d9479e9f9889a87a3c30c7f7ba537e5e59c4c85a37733b16e57c62df61302910160405180910390a150600192915050565b6033546001600160a01b031633146108a05760405162461bcd60e51b815260040161031f9061259b565b6108aa600061177d565b565b600054610100900460ff166108c75760005460ff16156108cb565b303b155b61092e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161031f565b600054610100900460ff16158015610950576000805461ffff19166101011790555b6109586117cf565b6109606117fe565b8015610972576000805461ff00191690555b50565b6060806000606760009054906101000a90046001600160a01b03166001600160a01b031663e3ed12a06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f1919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b03166358d0c5176040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6c919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b031663e45ef0916040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae7919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b03166389a302716040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b62919061272b565b9050826001600160a01b0316886001600160a01b03161480610b955750816001600160a01b0316886001600160a01b0316145b15610b9e578397505b836001600160a01b0316886001600160a01b03161480610bcf5750806001600160a01b0316886001600160a01b0316145b15610c615760408051600280825260608201835290916020830190803683370190505094508785600081518110610c0857610c086126fe565b60200260200101906001600160a01b031690816001600160a01b0316815250508685600181518110610c3c57610c3c6126fe565b60200260200101906001600160a01b031690816001600160a01b031681525050610d1f565b6040805160038082526080820190925290602082016060803683370190505094508785600081518110610c9657610c966126fe565b60200260200101906001600160a01b031690816001600160a01b0316815250508085600181518110610cca57610cca6126fe565b60200260200101906001600160a01b031690816001600160a01b0316815250508685600281518110610cfe57610cfe6126fe565b60200260200101906001600160a01b031690816001600160a01b0316815250505b50929695505050505050565b6033546000906001600160a01b03163314610d585760405162461bcd60e51b815260040161031f9061259b565b6040516370a0823160e01b8152306004820152610dd79083906001600160a01b038616906370a0823190602401602060405180830381865afa158015610da2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc69190612748565b6001600160a01b0386169190611715565b50600192915050565b6033546000906001600160a01b03163314610e0d5760405162461bcd60e51b815260040161031f9061259b565b6001600160a01b03831660009081526068602052604090205460ff1615610e6b5760405162461bcd60e51b8152602060048201526012602482015271141bdbdb08185b1c9958591e48185919195960721b604482015260640161031f565b6001600160a01b038316610ec15760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c2063616e6e6f74206265207a65726f20616464726573730000000000604482015260640161031f565b6001600160a01b038084166000818152606860209081526040808320805460ff19166001179055606990915280822080549487166001600160a01b031990951685179055517f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c9190a350600192915050565b6033546001600160a01b03163314610f5d5760405162461bcd60e51b815260040161031f9061259b565b6001600160a01b038116610fc25760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161031f565b6109728161177d565b6033546000906001600160a01b03163314610ff85760405162461bcd60e51b815260040161031f9061259b565b606680546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f53fb43152334e7d5afda4d474d9d4aa9a923ac1f1fbcd075db519cbb088f00a790600090a350600192915050565b600080600080606760009054906101000a90046001600160a01b03166001600160a01b03166358d0c5176040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110cc919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b031663e45ef0916040518163ffffffff1660e01b8152600401602060405180830381865afa158015611123573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611147919061272b565b905060008087156111685761115f8b8b8b60006103ea565b9250905061116b565b50875b836001600160a01b03168b6001600160a01b0316148061119c5750826001600160a01b03168b6001600160a01b0316145b156111b2576111ab8b82611825565b90506111c7565b6111c76001600160a01b038c16333084611b6b565b806111d2838b612627565b909c909b5091995090975050505050505050565b60006111f28686610975565b6001600160a01b0380871660009081526069602052604081205483519394506112489392169186918591611228576112286126fe565b60200260200101516001600160a01b0316611ba99092919063ffffffff16565b6001600160a01b03808616600090815260696020526040808220549051634401edf760e11b815291921690638803dbee9061128f9088908890879030904290600401612761565b6000604051808303816000875af11580156112ae573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112d69190810190612658565b90506112e481888686611c5b565b50505050505050565b60008060006112fc8686610975565b6001600160a01b0380871660009081526069602052604080822054905163d06ca61f60e01b8152939450909291169063d06ca61f90611341908890869060040161263f565b600060405180830381865afa15801561135e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113869190810190612658565b9050600081600184516113999190612714565b815181106113a9576113a96126fe565b6020908102919091018101516001600160a01b03808a16600090815260699093526040909220549092506113e2918a8116911688611ba9565b6001600160a01b038088166000908152606960205260408120549091166338ed1739886103e8611414866103e36125e6565b61141e9190612605565b8730426040518663ffffffff1660e01b8152600401611441959493929190612761565b6000604051808303816000875af1158015611460573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114889190810190612658565b905080600182516114999190612714565b815181106114a9576114a96126fe565b60200260200101516000146114e45780600182516114c79190612714565b815181106114d7576114d76126fe565b602002602001015161150c565b80600282516114f39190612714565b81518110611503576115036126fe565b60200260200101515b915060006103e86065548461152191906125e6565b61152b9190612605565b90506115378184612714565b9a909950975050505050505050565b6001600160a01b038416611558573393505b606754604080516319589bf760e01b815290516000926001600160a01b0316916319589bf79160048083019260209291908290030181865afa1580156115a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c6919061272b565b6066549091506115e3906001600160a01b03848116911688611ba9565b606654604051630b89c46960e41b81526001600160a01b039091169063b89c469090611617908990879089906004016127f5565b600060405180830381600087803b15801561163157600080fd5b505af1158015611645573d6000803e3d6000fd5b505060405163244643bb60e21b81526001600160a01b03841692506391190eec915061167d90889086908b908a908a9060040161282a565b600060405180830381600087803b15801561169757600080fd5b505af11580156116ab573d6000803e3d6000fd5b50505050816001600160a01b0316856001600160a01b03166116ca3390565b6001600160a01b03167e12b4dc130e5379076303f29877ad0e9e70a47c475cafead200cfe4babfb01087878b6040516117059392919061286f565b60405180910390a4505050505050565b6040516001600160a01b03831660248201526044810182905261177890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612056565b505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166117f65760405162461bcd60e51b815260040161031f906128a5565b6108aa612128565b600054610100900460ff166108aa5760405162461bcd60e51b815260040161031f906128a5565b6000808290506000606760009054906101000a90046001600160a01b03166001600160a01b03166358d0c5176040518163ffffffff1660e01b8152600401602060405180830381865afa158015611880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a4919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b031663e45ef0916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191f919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b0316634cf088d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611976573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199a919061272b565b9050816001600160a01b0316876001600160a01b03161415611abc57604051637c2b323560e01b8152600481018790526000906001600160a01b03841690637c2b323590602401602060405180830381865afa1580156119fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a229190612748565b9050611a396001600160a01b038416333084611b6b565b611a4d6001600160a01b0384168483611ba9565b604051636f074d1f60e11b8152600481018290526001600160a01b0384169063de0e9a3e906024016020604051808303816000875af1158015611a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab89190612748565b9450505b826001600160a01b0316876001600160a01b03161415611aeb57611aeb6001600160a01b038416333087611b6b565b611aff6001600160a01b0384168286611ba9565b6040516327afaa2360e21b815260048101859052600060248201526001600160a01b03821690639ebea88c90604401600060405180830381600087803b158015611b4857600080fd5b505af1158015611b5c573d6000803e3d6000fd5b50959998505050505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052611ba39085906323b872dd60e01b90608401611741565b50505050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015611bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1e9190612748565b611c289190612627565b6040516001600160a01b038516602482015260448101829052909150611ba390859063095ea7b360e01b90606401611741565b6067546040805163071f689560e51b815290516000926001600160a01b03169163e3ed12a09160048083019260209291908290030181865afa158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc9919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b03166358d0c5176040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d44919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b031663e45ef0916040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbf919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b03166377b818956040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e3a919061272b565b9050600088600081518110611e5157611e516126fe565b6020026020010151600014611e805788600081518110611e7357611e736126fe565b6020026020010151611e9c565b88600181518110611e9357611e936126fe565b60200260200101515b611ea69088612714565b9050836001600160a01b0316886001600160a01b03161480611ed95750826001600160a01b0316886001600160a01b0316145b1561203757611ef26001600160a01b0386168383611ba9565b60405163534a7e1d60e11b8152600481018290526001600160a01b0383169063a694fc3a90602401600060405180830381600087803b158015611f3457600080fd5b505af1158015611f48573d6000803e3d6000fd5b50505050836001600160a01b0316886001600160a01b03161415611f7f57611f7a6001600160a01b0385168783611715565b61204b565b826001600160a01b0316886001600160a01b03161415611f7a57611fad6001600160a01b0385168483611ba9565b604051630ea598cb60e41b8152600481018290526000906001600160a01b0385169063ea598cb0906024016020604051808303816000875af1158015611ff7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201b9190612748565b90506120316001600160a01b0385168883611715565b5061204b565b61204b6001600160a01b0389168783611715565b505050505050505050565b60006120ab826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166121589092919063ffffffff16565b80519091501561177857808060200190518101906120c991906128f0565b6117785760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161031f565b600054610100900460ff1661214f5760405162461bcd60e51b815260040161031f906128a5565b6108aa3361177d565b60606121678484600085612171565b90505b9392505050565b6060824710156121d25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161031f565b6001600160a01b0385163b6122295760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161031f565b600080866001600160a01b03168587604051612245919061290d565b60006040518083038185875af1925050503d8060008114612282576040519150601f19603f3d011682016040523d82523d6000602084013e612287565b606091505b50915091506122978282866122a2565b979650505050505050565b606083156122b157508161216a565b8251156122c15782518084602001fd5b8160405162461bcd60e51b815260040161031f9190612929565b6001600160a01b038116811461097257600080fd5b6000806040838503121561230357600080fd5b823561230e816122db565b9150602083013561231e816122db565b809150509250929050565b801515811461097257600080fd5b6000806000806080858703121561234d57600080fd5b8435612358816122db565b93506020850135612368816122db565b925060408501359150606085013561237f81612329565b939692955090935050565b60006020828403121561239c57600080fd5b813561216a816122db565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156123e6576123e66123a7565b604052919050565b600082601f8301126123ff57600080fd5b813567ffffffffffffffff811115612419576124196123a7565b61242c601f8201601f19166020016123bd565b81815284602083860101111561244157600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600080600080610100898b03121561247b57600080fd5b8835612486816122db565b97506020890135612496816122db565b96506040890135955060608901356124ad81612329565b945060808901356124bd816122db565b935060a089013567ffffffffffffffff808211156124da57600080fd5b6124e68c838d016123ee565b945060c08b01359150808211156124fc57600080fd5b506125098b828c016123ee565b92505060e089013561251a816122db565b809150509295985092959890939650565b60006020828403121561253d57600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561257d5781516001600160a01b031687529582019590820190600101612558565b509495945050505050565b60208152600061216a6020830184612544565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615612600576126006125d0565b500290565b60008261262257634e487b7160e01b600052601260045260246000fd5b500490565b6000821982111561263a5761263a6125d0565b500190565b8281526040602082015260006121676040830184612544565b6000602080838503121561266b57600080fd5b825167ffffffffffffffff8082111561268357600080fd5b818501915085601f83011261269757600080fd5b8151818111156126a9576126a96123a7565b8060051b91506126ba8483016123bd565b81815291830184019184810190888411156126d457600080fd5b938501935b838510156126f2578451825293850193908501906126d9565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b600082821015612726576127266125d0565b500390565b60006020828403121561273d57600080fd5b815161216a816122db565b60006020828403121561275a57600080fd5b5051919050565b85815284602082015260a06040820152600061278060a0830186612544565b6001600160a01b0394909416606083015250608001529392505050565b60005b838110156127b85781810151838201526020016127a0565b83811115611ba35750506000910152565b600081518084526127e181602086016020860161279d565b601f01601f19169290920160200192915050565b83815260606020820152600061280e60608301856127c9565b828103604084015261282081856127c9565b9695505050505050565b6001600160a01b038681168252851660208201526040810184905260a06060820181905260009061285d908301856127c9565b82810360808401526126f281856127c9565b60608152600061288260608301866127c9565b828103602084015261289481866127c9565b915050826040830152949350505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60006020828403121561290257600080fd5b815161216a81612329565b6000825161291f81846020870161279d565b9190910192915050565b60208152600061216a60208301846127c956fea264697066735822122040a317ee5b92b8796d9b24267f4d3c79b031e662eeb2d1b4e2949b8ddacb61cc64736f6c634300080b0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101215760003560e01c80638129fc1c116100ad578063d31e333011610071578063d31e333014610283578063de260f3714610296578063eb511dd4146102b9578063f2fde38b146102cc578063f772fc8b146102df57600080fd5b80638129fc1c1461020e5780638da5cb5b14610216578063aac2636914610227578063be9e09d614610250578063bf03ed901461027057600080fd5b8063497767c8116100f4578063497767c8146101b457806367d944fd146101c957806369e15404146101dc5780636b392680146101f3578063715018a61461020657600080fd5b8063146d17d6146101265780631824d43914610156578063284fd724146101795780633b7d0946146101a1575b600080fd5b606654610139906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101696101643660046122f0565b6102f2565b604051901515815260200161014d565b61018c610187366004612337565b6103ea565b6040805192835260208301919091520161014d565b6101696101af36600461238a565b610511565b6101c76101c236600461245e565b6105e5565b005b6101696101d736600461238a565b61077b565b6101e560655481565b60405190815260200161014d565b61016961020136600461252b565b6107ff565b6101c7610876565b6101c76108ac565b6033546001600160a01b0316610139565b61013961023536600461238a565b6069602052600090815260409020546001600160a01b031681565b61026361025e3660046122f0565b610975565b60405161014d9190612588565b606754610139906001600160a01b031681565b6101696102913660046122f0565b610d2b565b6101696102a436600461238a565b60686020526000908152604090205460ff1681565b6101696102c73660046122f0565b610de0565b6101c76102da36600461238a565b610f33565b6101696102ed36600461238a565b610fcb565b6033546000906001600160a01b031633146103285760405162461bcd60e51b815260040161031f9061259b565b60405180910390fd5b6001600160a01b03831660009081526068602052604090205460ff166103815760405162461bcd60e51b815260206004820152600e60248201526d141bdbdb081b9bdd08185919195960921b604482015260640161031f565b6001600160a01b0380841660008181526069602052604080822080548786166001600160a01b0319821681179092559151919094169392849290917f0732c0739d0dd4f51f2aab3a4d98921f06be03d94f3f04970bff2285e834d8109190a45060019392505050565b60008060006103e86065548661040091906125e6565b61040a9190612605565b905060006104188287612627565b9050866001600160a01b0316886001600160a01b03161461050557600061043f8989610975565b6001600160a01b03808a166000908152606960205260408082205490516307c0329d60e21b81529394509092911690631f00ca7490610484908690869060040161263f565b600060405180830381865afa1580156104a1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104c99190810190612658565b90506103e8816000815181106104e1576104e16126fe565b60200260200101516103e96104f691906125e6565b6105009190612605565b925050505b97909650945050505050565b6033546000906001600160a01b0316331461053e5760405162461bcd60e51b815260040161031f9061259b565b6001600160a01b03821660009081526068602052604090205460ff166105975760405162461bcd60e51b815260206004820152600e60248201526d141bdbdb081b9bdd08185919195960921b604482015260640161031f565b6001600160a01b038216600081815260686020526040808220805460ff19169055517f4106dfdaa577573db51c0ca93f766dbedfa0758faa2e7f5bcdb7c142be803c3f9190a2506001919050565b6001600160a01b03871660009081526068602052604090205460ff1661064d5760405162461bcd60e51b815260206004820152601760248201527f4e6f742061204d6f737320436172626f6e20546f6b656e000000000000000000604482015260640161031f565b600080600061065e8b8b8b8b61104f565b925092509250896001600160a01b03168b6001600160a01b0316146106aa578715610695576106908b8b8486886111e6565b6106d9565b6106a08b8b856112ed565b90995090506106d9565b876106d9576103e86065548a6106c091906125e6565b6106ca9190612605565b90506106d6818a612714565b98505b6106e6898888888e611546565b6065541561076e57606754604080516361d027b360e01b8152905161076e926001600160a01b0316916361d027b39160048083019260209291908290030181865afa158015610739573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075d919061272b565b6001600160a01b038c169083611715565b5050505050505050505050565b6033546000906001600160a01b031633146107a85760405162461bcd60e51b815260040161031f9061259b565b606780546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f3aaa975adcdc1f75217a6f792ef93a0b0df6b936db83c930741075efbebffe3190600090a350600192915050565b6033546000906001600160a01b0316331461082c5760405162461bcd60e51b815260040161031f9061259b565b606580549083905560408051828152602081018590527f528d9479e9f9889a87a3c30c7f7ba537e5e59c4c85a37733b16e57c62df61302910160405180910390a150600192915050565b6033546001600160a01b031633146108a05760405162461bcd60e51b815260040161031f9061259b565b6108aa600061177d565b565b600054610100900460ff166108c75760005460ff16156108cb565b303b155b61092e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161031f565b600054610100900460ff16158015610950576000805461ffff19166101011790555b6109586117cf565b6109606117fe565b8015610972576000805461ff00191690555b50565b6060806000606760009054906101000a90046001600160a01b03166001600160a01b031663e3ed12a06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f1919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b03166358d0c5176040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6c919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b031663e45ef0916040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae7919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b03166389a302716040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b62919061272b565b9050826001600160a01b0316886001600160a01b03161480610b955750816001600160a01b0316886001600160a01b0316145b15610b9e578397505b836001600160a01b0316886001600160a01b03161480610bcf5750806001600160a01b0316886001600160a01b0316145b15610c615760408051600280825260608201835290916020830190803683370190505094508785600081518110610c0857610c086126fe565b60200260200101906001600160a01b031690816001600160a01b0316815250508685600181518110610c3c57610c3c6126fe565b60200260200101906001600160a01b031690816001600160a01b031681525050610d1f565b6040805160038082526080820190925290602082016060803683370190505094508785600081518110610c9657610c966126fe565b60200260200101906001600160a01b031690816001600160a01b0316815250508085600181518110610cca57610cca6126fe565b60200260200101906001600160a01b031690816001600160a01b0316815250508685600281518110610cfe57610cfe6126fe565b60200260200101906001600160a01b031690816001600160a01b0316815250505b50929695505050505050565b6033546000906001600160a01b03163314610d585760405162461bcd60e51b815260040161031f9061259b565b6040516370a0823160e01b8152306004820152610dd79083906001600160a01b038616906370a0823190602401602060405180830381865afa158015610da2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc69190612748565b6001600160a01b0386169190611715565b50600192915050565b6033546000906001600160a01b03163314610e0d5760405162461bcd60e51b815260040161031f9061259b565b6001600160a01b03831660009081526068602052604090205460ff1615610e6b5760405162461bcd60e51b8152602060048201526012602482015271141bdbdb08185b1c9958591e48185919195960721b604482015260640161031f565b6001600160a01b038316610ec15760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c2063616e6e6f74206265207a65726f20616464726573730000000000604482015260640161031f565b6001600160a01b038084166000818152606860209081526040808320805460ff19166001179055606990915280822080549487166001600160a01b031990951685179055517f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c9190a350600192915050565b6033546001600160a01b03163314610f5d5760405162461bcd60e51b815260040161031f9061259b565b6001600160a01b038116610fc25760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161031f565b6109728161177d565b6033546000906001600160a01b03163314610ff85760405162461bcd60e51b815260040161031f9061259b565b606680546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f53fb43152334e7d5afda4d474d9d4aa9a923ac1f1fbcd075db519cbb088f00a790600090a350600192915050565b600080600080606760009054906101000a90046001600160a01b03166001600160a01b03166358d0c5176040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110cc919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b031663e45ef0916040518163ffffffff1660e01b8152600401602060405180830381865afa158015611123573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611147919061272b565b905060008087156111685761115f8b8b8b60006103ea565b9250905061116b565b50875b836001600160a01b03168b6001600160a01b0316148061119c5750826001600160a01b03168b6001600160a01b0316145b156111b2576111ab8b82611825565b90506111c7565b6111c76001600160a01b038c16333084611b6b565b806111d2838b612627565b909c909b5091995090975050505050505050565b60006111f28686610975565b6001600160a01b0380871660009081526069602052604081205483519394506112489392169186918591611228576112286126fe565b60200260200101516001600160a01b0316611ba99092919063ffffffff16565b6001600160a01b03808616600090815260696020526040808220549051634401edf760e11b815291921690638803dbee9061128f9088908890879030904290600401612761565b6000604051808303816000875af11580156112ae573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112d69190810190612658565b90506112e481888686611c5b565b50505050505050565b60008060006112fc8686610975565b6001600160a01b0380871660009081526069602052604080822054905163d06ca61f60e01b8152939450909291169063d06ca61f90611341908890869060040161263f565b600060405180830381865afa15801561135e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113869190810190612658565b9050600081600184516113999190612714565b815181106113a9576113a96126fe565b6020908102919091018101516001600160a01b03808a16600090815260699093526040909220549092506113e2918a8116911688611ba9565b6001600160a01b038088166000908152606960205260408120549091166338ed1739886103e8611414866103e36125e6565b61141e9190612605565b8730426040518663ffffffff1660e01b8152600401611441959493929190612761565b6000604051808303816000875af1158015611460573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114889190810190612658565b905080600182516114999190612714565b815181106114a9576114a96126fe565b60200260200101516000146114e45780600182516114c79190612714565b815181106114d7576114d76126fe565b602002602001015161150c565b80600282516114f39190612714565b81518110611503576115036126fe565b60200260200101515b915060006103e86065548461152191906125e6565b61152b9190612605565b90506115378184612714565b9a909950975050505050505050565b6001600160a01b038416611558573393505b606754604080516319589bf760e01b815290516000926001600160a01b0316916319589bf79160048083019260209291908290030181865afa1580156115a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c6919061272b565b6066549091506115e3906001600160a01b03848116911688611ba9565b606654604051630b89c46960e41b81526001600160a01b039091169063b89c469090611617908990879089906004016127f5565b600060405180830381600087803b15801561163157600080fd5b505af1158015611645573d6000803e3d6000fd5b505060405163244643bb60e21b81526001600160a01b03841692506391190eec915061167d90889086908b908a908a9060040161282a565b600060405180830381600087803b15801561169757600080fd5b505af11580156116ab573d6000803e3d6000fd5b50505050816001600160a01b0316856001600160a01b03166116ca3390565b6001600160a01b03167e12b4dc130e5379076303f29877ad0e9e70a47c475cafead200cfe4babfb01087878b6040516117059392919061286f565b60405180910390a4505050505050565b6040516001600160a01b03831660248201526044810182905261177890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612056565b505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166117f65760405162461bcd60e51b815260040161031f906128a5565b6108aa612128565b600054610100900460ff166108aa5760405162461bcd60e51b815260040161031f906128a5565b6000808290506000606760009054906101000a90046001600160a01b03166001600160a01b03166358d0c5176040518163ffffffff1660e01b8152600401602060405180830381865afa158015611880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a4919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b031663e45ef0916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191f919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b0316634cf088d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611976573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199a919061272b565b9050816001600160a01b0316876001600160a01b03161415611abc57604051637c2b323560e01b8152600481018790526000906001600160a01b03841690637c2b323590602401602060405180830381865afa1580156119fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a229190612748565b9050611a396001600160a01b038416333084611b6b565b611a4d6001600160a01b0384168483611ba9565b604051636f074d1f60e11b8152600481018290526001600160a01b0384169063de0e9a3e906024016020604051808303816000875af1158015611a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab89190612748565b9450505b826001600160a01b0316876001600160a01b03161415611aeb57611aeb6001600160a01b038416333087611b6b565b611aff6001600160a01b0384168286611ba9565b6040516327afaa2360e21b815260048101859052600060248201526001600160a01b03821690639ebea88c90604401600060405180830381600087803b158015611b4857600080fd5b505af1158015611b5c573d6000803e3d6000fd5b50959998505050505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052611ba39085906323b872dd60e01b90608401611741565b50505050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015611bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1e9190612748565b611c289190612627565b6040516001600160a01b038516602482015260448101829052909150611ba390859063095ea7b360e01b90606401611741565b6067546040805163071f689560e51b815290516000926001600160a01b03169163e3ed12a09160048083019260209291908290030181865afa158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc9919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b03166358d0c5176040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d44919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b031663e45ef0916040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbf919061272b565b90506000606760009054906101000a90046001600160a01b03166001600160a01b03166377b818956040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e3a919061272b565b9050600088600081518110611e5157611e516126fe565b6020026020010151600014611e805788600081518110611e7357611e736126fe565b6020026020010151611e9c565b88600181518110611e9357611e936126fe565b60200260200101515b611ea69088612714565b9050836001600160a01b0316886001600160a01b03161480611ed95750826001600160a01b0316886001600160a01b0316145b1561203757611ef26001600160a01b0386168383611ba9565b60405163534a7e1d60e11b8152600481018290526001600160a01b0383169063a694fc3a90602401600060405180830381600087803b158015611f3457600080fd5b505af1158015611f48573d6000803e3d6000fd5b50505050836001600160a01b0316886001600160a01b03161415611f7f57611f7a6001600160a01b0385168783611715565b61204b565b826001600160a01b0316886001600160a01b03161415611f7a57611fad6001600160a01b0385168483611ba9565b604051630ea598cb60e41b8152600481018290526000906001600160a01b0385169063ea598cb0906024016020604051808303816000875af1158015611ff7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201b9190612748565b90506120316001600160a01b0385168883611715565b5061204b565b61204b6001600160a01b0389168783611715565b505050505050505050565b60006120ab826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166121589092919063ffffffff16565b80519091501561177857808060200190518101906120c991906128f0565b6117785760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161031f565b600054610100900460ff1661214f5760405162461bcd60e51b815260040161031f906128a5565b6108aa3361177d565b60606121678484600085612171565b90505b9392505050565b6060824710156121d25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161031f565b6001600160a01b0385163b6122295760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161031f565b600080866001600160a01b03168587604051612245919061290d565b60006040518083038185875af1925050503d8060008114612282576040519150601f19603f3d011682016040523d82523d6000602084013e612287565b606091505b50915091506122978282866122a2565b979650505050505050565b606083156122b157508161216a565b8251156122c15782518084602001fd5b8160405162461bcd60e51b815260040161031f9190612929565b6001600160a01b038116811461097257600080fd5b6000806040838503121561230357600080fd5b823561230e816122db565b9150602083013561231e816122db565b809150509250929050565b801515811461097257600080fd5b6000806000806080858703121561234d57600080fd5b8435612358816122db565b93506020850135612368816122db565b925060408501359150606085013561237f81612329565b939692955090935050565b60006020828403121561239c57600080fd5b813561216a816122db565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156123e6576123e66123a7565b604052919050565b600082601f8301126123ff57600080fd5b813567ffffffffffffffff811115612419576124196123a7565b61242c601f8201601f19166020016123bd565b81815284602083860101111561244157600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600080600080610100898b03121561247b57600080fd5b8835612486816122db565b97506020890135612496816122db565b96506040890135955060608901356124ad81612329565b945060808901356124bd816122db565b935060a089013567ffffffffffffffff808211156124da57600080fd5b6124e68c838d016123ee565b945060c08b01359150808211156124fc57600080fd5b506125098b828c016123ee565b92505060e089013561251a816122db565b809150509295985092959890939650565b60006020828403121561253d57600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561257d5781516001600160a01b031687529582019590820190600101612558565b509495945050505050565b60208152600061216a6020830184612544565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615612600576126006125d0565b500290565b60008261262257634e487b7160e01b600052601260045260246000fd5b500490565b6000821982111561263a5761263a6125d0565b500190565b8281526040602082015260006121676040830184612544565b6000602080838503121561266b57600080fd5b825167ffffffffffffffff8082111561268357600080fd5b818501915085601f83011261269757600080fd5b8151818111156126a9576126a96123a7565b8060051b91506126ba8483016123bd565b81815291830184019184810190888411156126d457600080fd5b938501935b838510156126f2578451825293850193908501906126d9565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b600082821015612726576127266125d0565b500390565b60006020828403121561273d57600080fd5b815161216a816122db565b60006020828403121561275a57600080fd5b5051919050565b85815284602082015260a06040820152600061278060a0830186612544565b6001600160a01b0394909416606083015250608001529392505050565b60005b838110156127b85781810151838201526020016127a0565b83811115611ba35750506000910152565b600081518084526127e181602086016020860161279d565b601f01601f19169290920160200192915050565b83815260606020820152600061280e60608301856127c9565b828103604084015261282081856127c9565b9695505050505050565b6001600160a01b038681168252851660208201526040810184905260a06060820181905260009061285d908301856127c9565b82810360808401526126f281856127c9565b60608152600061288260608301866127c9565b828103602084015261289481866127c9565b915050826040830152949350505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60006020828403121561290257600080fd5b815161216a81612329565b6000825161291f81846020870161279d565b9190910192915050565b60208152600061216a60208301846127c956fea264697066735822122040a317ee5b92b8796d9b24267f4d3c79b031e662eeb2d1b4e2949b8ddacb61cc64736f6c634300080b0033

Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.