// Contract: API3DAORevenueIncinerator
// Target function: function powWad(int256 x, int256 y) internal pure returns (int256)
//SPDX-License-Identifier: MIT

/***** 
 ***** this code and all instances and deployments of this code are provided as-is;
 ***** no guarantee, representation nor warranty (express or implied) is given as to the safety or any attribute of the code or smart contracts
 ***** users should proceed with caution and at their own risk.

               /\   
              /__\ 
             /\  /\    
            /__\/__\
           /\  /\  /\   
          /__\/__\/__\ 
         /\  /\  /\  /\ 
        /__\/__\/__\/__\
       /\  /\  /\  /\  /\ 
      /__\/__\/  \/__\/__\ 
     /\  /\  /    \  /\  /\
    /__\/__\/______\/__\/__\
   /\  /\  /\  /\  /\  /\  /\  
  /__\/__\/__\/__\/__\/__\/__\ 
 /\  /\  /\  /\  /\  /\  /\  /\
/__\/__\/__\/__\/__\/__\/__\/__\

 
⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ 

   API3DAO REVENUE INCINERATOR 

⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ 


*/

pragma solidity >=0.8.4;

/// @title API3DAO Revenue Incinerator

/** @notice immutable burn of excess USDC revenue by buying and burning API3 tokens per API3DAO whitepaper:
 *** swaps USDC sent to this contract for API3 tokens and ETH to LP in UniV2; each LP is then queued chronologically.
 *** LP position is redeemable to this contract after one year by any caller, which is swapped to API3 tokens via UniV2 and burned via the API3 token contract.
 *** ETH sent directly to this contract is auto-swapped to API3 tokens, which are then burned via the API3 token contract,
 *** providing an optional method for automated ETH revenue burning */

/** @dev be advised there is inherent slippage/MEV risk for large amounts,
 *** so it is recommended to call swapUSDCToAPI3AndLpWithETHPair() often, perhaps by bot;
 *** swapFractionUSDCToAPI3AndLpWithETHPair() may also be used to swap and LP less than the total balance of USDC at a time and further avoid such risks.
 **/
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author SolDAO (https://github.com/Sol-DAO/solbase/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /// -----------------------------------------------------------------------
    /// Custom Errors
    /// -----------------------------------------------------------------------

    /// @dev The operation failed, as the output exceeds the maximum value of uint256.
    error ExpOverflow();

    /// @dev The operation failed, as the output exceeds the maximum value of uint256.
    error FactorialOverflow();

    /// @dev The operation failed, due to an multiplication overflow.
    error MulWadFailed();

    /// @dev The operation failed, either due to a
    /// multiplication overflow, or a division by a zero.
    error DivWadFailed();

    /// @dev The multiply-divide operation failed, either due to a
    /// multiplication overflow, or a division by a zero.
    error MulDivFailed();

    /// @dev The division failed, as the denominator is zero.
    error DivFailed();

    /// @dev The output is undefined, as the input is less-than-or-equal to zero.
    error LnWadUndefined();

    /// @dev The output is undefined, as the input is zero.
    error Log2Undefined();

    /// -----------------------------------------------------------------------
    /// Constants
    /// -----------------------------------------------------------------------

    /// @dev The maximum possible integer.
    uint256 internal constant MAX_UINT256 = 2 ** 256 - 1;

    /// @dev The scalar of ETH and most ERC20s.
    uint256 internal constant WAD = 1e18;

    /// -----------------------------------------------------------------------
    /// Simplified Fixed Point Operations
    /// -----------------------------------------------------------------------

    /// @dev Equivalent to `(x * y) / WAD` rounded down.
    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            if mul(y, gt(x, div(not(0), y))) {
                // Store the function selector of `MulWadFailed()`.
                mstore(0x00, 0xbac65e5b)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            z := div(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded up.
    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            if mul(y, gt(x, div(not(0), y))) {
                // Store the function selector of `MulWadFailed()`.
                mstore(0x00, 0xbac65e5b)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down.
    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
            if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
                // Store the function selector of `DivWadFailed()`.
                mstore(0x00, 0x7c5f487d)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            z := div(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded up.
    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
            if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
                // Store the function selector of `DivWadFailed()`.
                mstore(0x00, 0x7c5f487d)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
        }
    }