ETH Price: $2,318.89 (-3.56%)
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
KeeperFee

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 500 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

import {FlatcoinErrors} from "../libraries/FlatcoinErrors.sol";
import {FlatcoinModuleKeys} from "../libraries/FlatcoinModuleKeys.sol";

// Interfaces
import {IOracleModule} from "../interfaces/IOracleModule.sol";
import {IGasPriceOracle} from "../interfaces/IGasPriceOracle.sol";
import {IChainlinkAggregatorV3} from "../interfaces/IChainlinkAggregatorV3.sol";

/// @title KeeperFee
/// @notice A dynamic gas fee module to be used on L2s.
/// @dev Adapted from Synthetix PerpsV2DynamicFeesModule.
///      See https://sips.synthetix.io/sips/sip-2013
contract KeeperFee is Ownable {
    using Math for uint256;

    bytes32 public constant MODULE_KEY = FlatcoinModuleKeys._KEEPER_FEE_MODULE_KEY;

    IChainlinkAggregatorV3 private _ethOracle; // ETH price for gas unit conversions
    IGasPriceOracle private _gasPriceOracle = IGasPriceOracle(0x420000000000000000000000000000000000000F); // gas price oracle as deployed on Optimism L2 rollups
    IOracleModule private _oracleModule; // for collateral asset pricing (the flatcoin market)

    uint256 private constant _UNIT = 10 ** 18;
    uint256 private immutable _STALENESS_PERIOD;

    address private _assetToPayWith;
    uint256 private _profitMarginUSD;
    uint256 private _profitMarginPercent;
    uint256 private _keeperFeeUpperBound;
    uint256 private _keeperFeeLowerBound;
    uint256 private _gasUnitsL1;
    uint256 private _gasUnitsL2;

    constructor(
        address owner,
        address ethOracle,
        address oracleModule,
        address assetToPayWith,
        uint256 profitMarginUSD,
        uint256 profitMarginPercent,
        uint256 keeperFeeUpperBound,
        uint256 keeperFeeLowerBound,
        uint256 gasUnitsL1,
        uint256 gasUnitsL2,
        uint256 stalenessPeriod
    ) Ownable(owner) {
        // contracts
        _ethOracle = IChainlinkAggregatorV3(ethOracle);
        _oracleModule = IOracleModule(oracleModule);

        // params
        _assetToPayWith = assetToPayWith;
        _profitMarginUSD = profitMarginUSD;
        _profitMarginPercent = profitMarginPercent;
        _keeperFeeUpperBound = keeperFeeUpperBound; // In USD
        _keeperFeeLowerBound = keeperFeeLowerBound; // In USD
        _gasUnitsL1 = gasUnitsL1;
        _gasUnitsL2 = gasUnitsL2;
        _STALENESS_PERIOD = stalenessPeriod;

        // Check that the oracle asset price is valid
        (uint256 assetPrice, ) = IOracleModule(oracleModule).getPrice();

        if (assetPrice <= 0) revert FlatcoinErrors.PriceInvalid(FlatcoinErrors.PriceSource.OnChain);

        (, , , uint256 ethPriceupdatedAt, ) = _ethOracle.latestRoundData();

        // Check that the ETH oracle price is fresh.
        if (block.timestamp >= ethPriceupdatedAt + stalenessPeriod)
            revert FlatcoinErrors.ETHPriceStale();
    }

    /////////////////////////////////////////////
    //             View Functions              //
    /////////////////////////////////////////////

    /// @dev Returns computed gas price given on-chain variables.
    function getKeeperFee() public view returns (uint256 keeperFeeCollateral) {
        return getKeeperFee(_gasPriceOracle.baseFee());
    }

    function getKeeperFee(uint256 baseFee) public view returns (uint256 keeperFeeCollateral) {
        uint256 ethPrice18;
        uint256 collateralPrice;
        {
            uint256 timestamp;

            (, int256 ethPrice, , uint256 ethPriceupdatedAt, ) = _ethOracle.latestRoundData();

            if (block.timestamp >= ethPriceupdatedAt + _STALENESS_PERIOD) revert FlatcoinErrors.ETHPriceStale();
            if (ethPrice <= 0) revert FlatcoinErrors.ETHPriceInvalid();

            ethPrice18 = uint256(ethPrice) * 1e10; // from 8 decimals to 18
            // NOTE: Currently the market asset and collateral asset are the same.
            // If this changes in the future, then the following line should fetch the collateral asset, not market asset.
            (, uint32 maxAge) = _oracleModule.onchainOracle();
            (collateralPrice, timestamp) = _oracleModule.getPrice();

            if (collateralPrice <= 0) revert FlatcoinErrors.PriceInvalid(FlatcoinErrors.PriceSource.OnChain);

            if (block.timestamp >= timestamp + maxAge)
                revert FlatcoinErrors.PriceStale(FlatcoinErrors.PriceSource.OnChain);
        }

        bool isEcotone;
        try _gasPriceOracle.isEcotone() returns (bool _isEcotone) {
            isEcotone = _isEcotone;
        } catch {
            // If the call fails, we assume it's not an ecotone. Explicitly setting it to false to avoid missunderstandings.
            isEcotone = false;
        }

        uint256 costOfExecutionGrossEth;

        // Note: The OVM GasPriceOracle scales the L1 gas fee by the decimals
        // Reference function `_getL1FeeBedrock` https://github.com/ethereum-optimism/optimism/blob/af9aa3369de8c3cbef0e491024fb83590492366c/packages/contracts-bedrock/src/L2/GasPriceOracle.sol#L128
        // The Synthetix implementation can be found in function `getCostofExecutionEth` https://github.com/Synthetixio/synthetix-v3/blob/e7932e96d8153db0716f1e5dd6df78c1a1ec711e/auxiliary/OpGasPriceOracle/contracts/OpGasPriceOracle.sol#L72
        if (isEcotone) {
            // If it's an ecotone, use the new formula and interface
            uint256 gasPriceL2 = baseFee;
            uint256 baseFeeScalar = _gasPriceOracle.baseFeeScalar();
            uint256 l1BaseFee = _gasPriceOracle.l1BaseFee();
            uint256 blobBaseFeeScalar = _gasPriceOracle.blobBaseFeeScalar();
            uint256 blobBaseFee = _gasPriceOracle.blobBaseFee();
            uint256 decimals = _gasPriceOracle.decimals();

            uint256 l1GasPrice = (baseFeeScalar * l1BaseFee * 16 + blobBaseFeeScalar * blobBaseFee) /
                (16 * 10 ** decimals);

            costOfExecutionGrossEth = ((_gasUnitsL1 * l1GasPrice) + (_gasUnitsL2 * gasPriceL2));
        } else {
            // If it's not an ecotone, use the legacy formula and interface.
            uint256 gasPriceL2 = baseFee; // baseFee and gasPrice are the same in the legacy contract. Both return block.basefee.
            uint256 overhead = _gasPriceOracle.overhead();
            uint256 l1BaseFee = _gasPriceOracle.l1BaseFee();
            uint256 decimals = _gasPriceOracle.decimals();
            uint256 scalar = _gasPriceOracle.scalar();

            costOfExecutionGrossEth = ((((_gasUnitsL1 + overhead) * l1BaseFee * scalar) / 10 ** decimals) +
                (_gasUnitsL2 * gasPriceL2));
        }

        uint256 costOfExecutionGrossUSD = costOfExecutionGrossEth.mulDiv(ethPrice18, _UNIT); // fee priced in USD

        uint256 maxProfitMargin = _profitMarginUSD.max(costOfExecutionGrossUSD.mulDiv(_profitMarginPercent, _UNIT)); // additional USD profit for the keeper
        uint256 costOfExecutionNet = costOfExecutionGrossUSD + maxProfitMargin; // fee priced in USD

        keeperFeeCollateral = (_keeperFeeUpperBound.min(costOfExecutionNet.max(_keeperFeeLowerBound))).mulDiv(
            _UNIT,
            collateralPrice
        ); // fee priced in collateral
    }

    /// @dev Returns the current configurations.
    function getConfig()
        external
        view
        returns (
            address gasPriceOracle,
            uint256 profitMarginUSD,
            uint256 profitMarginPercent,
            uint256 keeperFeeUpperBound,
            uint256 keeperFeeLowerBound,
            uint256 gasUnitsL1,
            uint256 gasUnitsL2
        )
    {
        gasPriceOracle = address(_gasPriceOracle);
        profitMarginUSD = _profitMarginUSD;
        profitMarginPercent = _profitMarginPercent;
        keeperFeeUpperBound = _keeperFeeUpperBound;
        keeperFeeLowerBound = _keeperFeeLowerBound;
        gasUnitsL1 = _gasUnitsL1;
        gasUnitsL2 = _gasUnitsL2;
    }

    /////////////////////////////////////////////
    //             Owner Functions             //
    /////////////////////////////////////////////

    /// @dev Sets params used for gas price computation.
    function setParameters(
        uint256 profitMarginUSD,
        uint256 profitMarginPercent,
        uint256 keeperFeeUpperBound,
        uint256 keeperFeeLowerBound,
        uint256 gasUnitsL1,
        uint256 gasUnitsL2
    ) external onlyOwner {
        _profitMarginUSD = profitMarginUSD;
        _profitMarginPercent = profitMarginPercent;
        _keeperFeeUpperBound = keeperFeeUpperBound;
        _keeperFeeLowerBound = keeperFeeLowerBound;
        _gasUnitsL1 = gasUnitsL1;
        _gasUnitsL2 = gasUnitsL2;
    }

    /// @dev Sets keeper fee upper and lower bounds.
    /// @param keeperFeeUpperBound The upper bound of the keeper fee in USD.
    /// @param keeperFeeLowerBound The lower bound of the keeper fee in USD.
    function setParameters(uint256 keeperFeeUpperBound, uint256 keeperFeeLowerBound) external onlyOwner {
        if (keeperFeeUpperBound <= keeperFeeLowerBound) revert FlatcoinErrors.InvalidFee(keeperFeeLowerBound);
        if (keeperFeeLowerBound == 0) revert FlatcoinErrors.ZeroValue("keeperFeeLowerBound");

        _keeperFeeUpperBound = keeperFeeUpperBound;
        _keeperFeeLowerBound = keeperFeeLowerBound;
    }

    /// @dev Sets a custom gas price oracle. May be needed for some chain deployments.
    function setGasPriceOracle(address gasPriceOracle) external onlyOwner {
        if (address(gasPriceOracle) == address(0)) revert FlatcoinErrors.ZeroAddress("gasPriceOracle");

        _gasPriceOracle = IGasPriceOracle(gasPriceOracle);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

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

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

File 4 of 9 : FlatcoinErrors.sol
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity 0.8.20;

library FlatcoinErrors {
    enum PriceSource {
        OnChain,
        OffChain
    }

    error ZeroAddress(string variableName);

    error ZeroValue(string variableName);

    error Paused(bytes32 moduleKey);

    error OnlyOwner(address msgSender);

    error AmountTooSmall(uint256 amount, uint256 minAmount);

    error HighSlippage(uint256 supplied, uint256 accepted);

    /// @dev DelayedOrder
    error MaxFillPriceTooLow(uint256 maxFillPrice, uint256 currentPrice);

    /// @dev DelayedOrder
    error MinFillPriceTooHigh(uint256 minFillPrice, uint256 currentPrice);

    /// @dev DelayedOrder
    error NotEnoughMarginForFees(int256 marginAmount, uint256 feeAmount);

    /// @dev DelayedOrder
    error OrderHasExpired();

    /// @dev DelayedOrder
    error OrderHasNotExpired();

    /// @dev DelayedOrder
    error ExecutableTimeNotReached(uint256 executableTime);

    /// @dev DelayedOrder
    error NotTokenOwner(uint256 tokenId, address msgSender);

    /// @dev DelayedOrder
    error MaxSkewReached(uint256 skewFraction);

    /// @dev DelayedOrder
    error InvalidSkewFractionMax(uint256 skewFractionMax);

    /// @dev DelayedOrder
    error InvalidMaxVelocitySkew(uint256 maxVelocitySkew);

    /// @dev DelayedOrder
    error NotEnoughBalanceForWithdraw(address account, uint256 totalBalance, uint256 withdrawAmount);

    /// @dev DelayedOrder
    error WithdrawalTooSmall(uint256 withdrawAmount, uint256 keeperFee);

    /// @dev DelayedOrder
    error InvariantViolation(string variableName);

    /// @dev DelayedOrder
    error InvalidLeverageCriteria();

    /// @dev DelayedOrder
    error LeverageTooLow(uint256 leverageMin, uint256 leverage);

    /// @dev DelayedOrder
    error LeverageTooHigh(uint256 leverageMax, uint256 leverage);

    /// @dev DelayedOrder
    error MarginTooSmall(uint256 marginMin, uint256 margin);

    /// @dev DelayedOrder
    error DepositCapReached(uint256 collateralCap);

    /// @dev LimitOrder
    error LimitOrderInvalid(uint256 tokenId);

    /// @dev LimitOrder
    error LimitOrderPriceNotInRange(uint256 price, uint256 priceLowerThreshold, uint256 priceUpperThreshold);

    /// @dev LimitOrder
    error InvalidThresholds(uint256 priceLowerThreshold, uint256 priceUpperThreshold);

    error InvalidFee(uint256 fee);

    error OnlyAuthorizedModule(address msgSender);

    error ValueNotPositive(string variableName);

    /// @dev LeverageModule
    error MarginMismatchOnClose();

    /// @dev FlatcoinVault
    error InsufficientGlobalMargin();

    /// @dev OracleModule
    error RefundFailed();

    error PriceStale(PriceSource priceSource);

    error PriceInvalid(PriceSource priceSource);

    error PriceMismatch(uint256 diffPercent);

    /// @dev OracleModule
    error OracleConfigInvalid();

    /// @dev StableModule
    error PriceImpactDuringWithdraw();

    /// @dev StableModule
    error PriceImpactDuringFullWithdraw();

    /// @dev KeeperFee
    error ETHPriceInvalid();

    /// @dev KeeperFee
    error ETHPriceStale();

    /// @dev Error to emit when a leverage position is not liquidatable.
    /// @param tokenId The token ID of the position.
    error CannotLiquidate(uint256 tokenId);

    error InvalidBounds(uint256 lower, uint256 upper);

    error PositionCreatesBadDebt();

    error ModuleKeyEmpty();

    /// @dev PointsModule
    error MaxVarianceExceeded(string variableName);
}

File 5 of 9 : FlatcoinModuleKeys.sol
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity 0.8.20;

library FlatcoinModuleKeys {
    bytes32 internal constant _STABLE_MODULE_KEY = bytes32("stableModule");
    bytes32 internal constant _LEVERAGE_MODULE_KEY = bytes32("leverageModule");
    bytes32 internal constant _ORACLE_MODULE_KEY = bytes32("oracleModule");
    bytes32 internal constant _DELAYED_ORDER_KEY = bytes32("delayedOrder");
    bytes32 internal constant _LIMIT_ORDER_KEY = bytes32("limitOrder");
    bytes32 internal constant _LIQUIDATION_MODULE_KEY = bytes32("liquidationModule");
    bytes32 internal constant _KEEPER_FEE_MODULE_KEY = bytes32("keeperFee");
    bytes32 internal constant _POINTS_MODULE_KEY = bytes32("pointsModule");
}

// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.20;

import {IChainlinkAggregatorV3} from "./IChainlinkAggregatorV3.sol";

interface IOracleModule {
    function onchainOracle() external view returns (IChainlinkAggregatorV3 oracleContract, uint32 maxAge);

    function getPrice() external view returns (uint256 price, uint256 timestamp);

    function getPrice(uint32 maxAge, bool priceDiffCheck) external view returns (uint256 price, uint256 timestamp);

    function updatePythPrice(address sender, bytes[] calldata priceUpdateData) external payable;
}

// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.20;

interface IGasPriceOracle {
    function baseFee() external view returns (uint256 _baseFee);

    function baseFeeScalar() external view returns (uint32 _baseFeeScalar);

    function blobBaseFee() external view returns (uint256 _blobBaseFee);

    function blobBaseFeeScalar() external view returns (uint32 _blobBaseFeeScalar);

    function decimals() external pure returns (uint256 _decimals);

    function gasPrice() external view returns (uint256 _gasPrice);

    function getL1Fee(bytes memory _data) external view returns (uint256 _l1Fee);

    function getL1GasUsed(bytes memory _data) external view returns (uint256 _l1GasUsed);

    function isEcotone() external view returns (bool _isEcotone);

    function l1BaseFee() external view returns (uint256 _l1BaseFee);

    function overhead() external view returns (uint256 _overhead);

    function scalar() external view returns (uint256 _scalar);

    function setEcotone() external;

    function version() external view returns (string memory _version);
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.20;

interface IChainlinkAggregatorV3 {
    function decimals() external view returns (uint8 decimals);

    function latestRoundData()
        external
        view
        returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
    "pyth-sdk-solidity/=lib/pyth-sdk-solidity/",
    "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/",
    "ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 500
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"ethOracle","type":"address"},{"internalType":"address","name":"oracleModule","type":"address"},{"internalType":"address","name":"assetToPayWith","type":"address"},{"internalType":"uint256","name":"profitMarginUSD","type":"uint256"},{"internalType":"uint256","name":"profitMarginPercent","type":"uint256"},{"internalType":"uint256","name":"keeperFeeUpperBound","type":"uint256"},{"internalType":"uint256","name":"keeperFeeLowerBound","type":"uint256"},{"internalType":"uint256","name":"gasUnitsL1","type":"uint256"},{"internalType":"uint256","name":"gasUnitsL2","type":"uint256"},{"internalType":"uint256","name":"stalenessPeriod","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ETHPriceInvalid","type":"error"},{"inputs":[],"name":"ETHPriceStale","type":"error"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"InvalidFee","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"enum FlatcoinErrors.PriceSource","name":"priceSource","type":"uint8"}],"name":"PriceInvalid","type":"error"},{"inputs":[{"internalType":"enum FlatcoinErrors.PriceSource","name":"priceSource","type":"uint8"}],"name":"PriceStale","type":"error"},{"inputs":[{"internalType":"string","name":"variableName","type":"string"}],"name":"ZeroAddress","type":"error"},{"inputs":[{"internalType":"string","name":"variableName","type":"string"}],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"MODULE_KEY","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"internalType":"address","name":"gasPriceOracle","type":"address"},{"internalType":"uint256","name":"profitMarginUSD","type":"uint256"},{"internalType":"uint256","name":"profitMarginPercent","type":"uint256"},{"internalType":"uint256","name":"keeperFeeUpperBound","type":"uint256"},{"internalType":"uint256","name":"keeperFeeLowerBound","type":"uint256"},{"internalType":"uint256","name":"gasUnitsL1","type":"uint256"},{"internalType":"uint256","name":"gasUnitsL2","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getKeeperFee","outputs":[{"internalType":"uint256","name":"keeperFeeCollateral","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseFee","type":"uint256"}],"name":"getKeeperFee","outputs":[{"internalType":"uint256","name":"keeperFeeCollateral","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gasPriceOracle","type":"address"}],"name":"setGasPriceOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"profitMarginUSD","type":"uint256"},{"internalType":"uint256","name":"profitMarginPercent","type":"uint256"},{"internalType":"uint256","name":"keeperFeeUpperBound","type":"uint256"},{"internalType":"uint256","name":"keeperFeeLowerBound","type":"uint256"},{"internalType":"uint256","name":"gasUnitsL1","type":"uint256"},{"internalType":"uint256","name":"gasUnitsL2","type":"uint256"}],"name":"setParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keeperFeeUpperBound","type":"uint256"},{"internalType":"uint256","name":"keeperFeeLowerBound","type":"uint256"}],"name":"setParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a0604052600280546001600160a01b03191673420000000000000000000000000000000000000f1790553480156200003757600080fd5b50604051620015bb380380620015bb8339810160408190526200005a91620002aa565b8a6001600160a01b0381166200008b57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b62000096816200023d565b50600180546001600160a01b03808d166001600160a01b031992831617909255600380548c8416908316811790915560048054938c169390921692909217815560058990556006889055600787905560088690556009859055600a849055608083905260408051634c6afee560e11b81528151600094936398d5fdca9383820193909291908290030181865afa15801562000135573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200015b91906200034e565b5090506000811162000185576000604051630b1ba73960e21b815260040162000082919062000373565b60015460408051633fabe5a360e21b815290516000926001600160a01b03169163feaf968c9160048083019260a09291908290030181865afa158015620001d0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001f69190620003b4565b50935050505082816200020a919062000409565b42106200022a57604051631abf28d560e11b815260040160405180910390fd5b5050505050505050505050505062000431565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620002a557600080fd5b919050565b60008060008060008060008060008060006101608c8e031215620002cd57600080fd5b620002d88c6200028d565b9a50620002e860208d016200028d565b9950620002f860408d016200028d565b98506200030860608d016200028d565b975060808c0151965060a08c0151955060c08c0151945060e08c015193506101008c015192506101208c015191506101408c015190509295989b509295989b9093969950565b600080604083850312156200036257600080fd5b505080516020909101519092909150565b60208101600283106200039657634e487b7160e01b600052602160045260246000fd5b91905290565b80516001600160501b0381168114620002a557600080fd5b600080600080600060a08688031215620003cd57600080fd5b620003d8866200039c565b9450602086015193506040860151925060608601519150620003fd608087016200039c565b90509295509295909350565b808201808211156200042b57634e487b7160e01b600052601160045260246000fd5b92915050565b60805161116e6200044d60003960006102d8015261116e6000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c8063884870c711610066578063884870c7146101015780638da5cb5b14610114578063a4d0c0a91461012f578063c3f909d414610142578063f2fde38b1461019657600080fd5b8063282c8749146100a3578063354662e0146100b85780633d23b9ca146100d357806343880d38146100e6578063715018a6146100f9575b600080fd5b6100b66100b1366004610dc6565b6101a9565b005b6100c06101ce565b6040519081526020015b60405180910390f35b6100c0686b656570657246656560b81b81565b6100c06100f4366004610e09565b61024f565b6100b6610ae7565b6100b661010f366004610e22565b610afb565b6000546040516001600160a01b0390911681526020016100ca565b6100b661013d366004610e59565b610b82565b600254600554600654600754600854600954600a54604080516001600160a01b0390981688526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016100ca565b6100b66101a4366004610e59565b610c10565b6101b1610c4e565b600595909555600693909355600791909155600855600955600a55565b600061024a600260009054906101000a90046001600160a01b03166001600160a01b0316636ef25c3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610226573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f49190610e76565b905090565b600080600080600080600160009054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156102ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102cf9190610eae565b509350509250507f0000000000000000000000000000000000000000000000000000000000000000816103029190610f14565b421061032157604051631abf28d560e11b815260040160405180910390fd5b6000821361034257604051632702a96160e01b815260040160405180910390fd5b610351826402540be400610f27565b94506000600360009054906101000a90046001600160a01b03166001600160a01b031663779694666040518163ffffffff1660e01b81526004016040805180830381865afa1580156103a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cb9190610f52565b60035460408051634c6afee560e11b815281519395506001600160a01b0390921693506398d5fdca926004808401938290030181865afa158015610413573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104379190610f87565b909550935084610466576000604051630b1ba73960e21b815260040161045d9190610fab565b60405180910390fd5b61047663ffffffff821685610f14565b4210610498576000604051630c0ee27f60e31b815260040161045d9190610fab565b505050506000600260009054906101000a90046001600160a01b03166001600160a01b0316634ef6e2246040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561050d575060408051601f3d908101601f1916820190925261050a91810190610fd3565b60015b6105195750600061051c565b90505b6000811561081257600254604080516318b30b2360e31b8152905188926000926001600160a01b039091169163c5985918916004808201926020929091908290030181865afa158015610573573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105979190610ff5565b63ffffffff1690506000600260009054906101000a90046001600160a01b03166001600160a01b031663519b4bd36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106189190610e76565b90506000600260009054906101000a90046001600160a01b03166001600160a01b03166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa15801561066f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106939190610ff5565b63ffffffff1690506000600260009054906101000a90046001600160a01b03166001600160a01b031663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107149190610e76565b90506000600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561076b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078f9190610e76565b9050600061079e82600a6110f4565b6107a9906010610f27565b6107b38486610f27565b6107bd8789610f27565b6107c8906010610f27565b6107d29190610f14565b6107dc9190611116565b905086600a546107ec9190610f27565b816009546107fa9190610f27565b6108049190610f14565b975050505050505050610a51565b6002546040805163060c60b160e11b8152905188926000926001600160a01b0390911691630c18c162916004808201926020929091908290030181865afa158015610861573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108859190610e76565b90506000600260009054906101000a90046001600160a01b03166001600160a01b031663519b4bd36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109009190610e76565b90506000600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097b9190610e76565b90506000600260009054906101000a90046001600160a01b03166001600160a01b031663f45e65d86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f69190610e76565b905084600a54610a069190610f27565b610a1183600a6110f4565b828587600954610a219190610f14565b610a2b9190610f27565b610a359190610f27565b610a3f9190611116565b610a499190610f14565b955050505050505b6000610a668286670de0b6b3a7640000610c7b565b90506000610a95610a8c600654670de0b6b3a764000085610c7b9092919063ffffffff16565b60055490610d40565b90506000610aa38284610f14565b9050610ada670de0b6b3a764000087610ad3610aca60085486610d4090919063ffffffff16565b60075490610d5a565b9190610c7b565b9998505050505050505050565b610aef610c4e565b610af96000610d69565b565b610b03610c4e565b808211610b265760405163179c637760e11b81526004810182905260240161045d565b80600003610b775760405163046c82ad60e41b815260206004820152601360248201527f6b65657065724665654c6f776572426f756e6400000000000000000000000000604482015260640161045d565b600791909155600855565b610b8a610c4e565b6001600160a01b038116610be15760405163eac0d38960e01b815260206004820152600e60248201527f67617350726963654f7261636c65000000000000000000000000000000000000604482015260640161045d565b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b610c18610c4e565b6001600160a01b038116610c4257604051631e4fbdf760e01b81526000600482015260240161045d565b610c4b81610d69565b50565b6000546001600160a01b03163314610af95760405163118cdaa760e01b815233600482015260240161045d565b6000838302816000198587098281108382030391505080600003610cb257838281610ca857610ca8611100565b0492505050610d39565b808411610cd25760405163227bc15360e01b815260040160405180910390fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b6000818311610d4f5781610d51565b825b90505b92915050565b6000818310610d4f5781610d51565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060008060008060c08789031215610ddf57600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b600060208284031215610e1b57600080fd5b5035919050565b60008060408385031215610e3557600080fd5b50508035926020909101359150565b6001600160a01b0381168114610c4b57600080fd5b600060208284031215610e6b57600080fd5b8135610d3981610e44565b600060208284031215610e8857600080fd5b5051919050565b805169ffffffffffffffffffff81168114610ea957600080fd5b919050565b600080600080600060a08688031215610ec657600080fd5b610ecf86610e8f565b9450602086015193506040860151925060608601519150610ef260808701610e8f565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b80820180821115610d5457610d54610efe565b8082028115828204841417610d5457610d54610efe565b805163ffffffff81168114610ea957600080fd5b60008060408385031215610f6557600080fd5b8251610f7081610e44565b9150610f7e60208401610f3e565b90509250929050565b60008060408385031215610f9a57600080fd5b505080516020909101519092909150565b6020810160028310610fcd57634e487b7160e01b600052602160045260246000fd5b91905290565b600060208284031215610fe557600080fd5b81518015158114610d3957600080fd5b60006020828403121561100757600080fd5b610d5182610f3e565b600181815b8085111561104b57816000190482111561103157611031610efe565b8085161561103e57918102915b93841c9390800290611015565b509250929050565b60008261106257506001610d54565b8161106f57506000610d54565b8160018114611085576002811461108f576110ab565b6001915050610d54565b60ff8411156110a0576110a0610efe565b50506001821b610d54565b5060208310610133831016604e8410600b84101617156110ce575081810a610d54565b6110d88383611010565b80600019048211156110ec576110ec610efe565b029392505050565b6000610d518383611053565b634e487b7160e01b600052601260045260246000fd5b60008261113357634e487b7160e01b600052601260045260246000fd5b50049056fea26469706673582212204d5762bf5343af3efdb71903a20d1caa6f16d092a4e0bca7d8cacfef084d4dc664736f6c634300081400330000000000000000000000001677640787891022efec86828bc386828c68d2aa00000000000000000000000071041dddad3595f9ced3dccfbe3d1f4b0a16bb70000000000000000000000000aba633927bd8622fbbdd35d291a914c2fdaae1ff000000000000000000000000b6fe221fe9eef5aba221c348ba20a1bf5e73624c00000000000000000000000000000000000000000000000006f05b59d3b200000000000000000000000000000000000000000000000000000429d069189e0000000000000000000000000000000000000000000000000001a055690d9db8000000000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000075300000000000000000000000000000000000000000000000000000000000124f8000000000000000000000000000000000000000000000000000000000000004b0

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061009e5760003560e01c8063884870c711610066578063884870c7146101015780638da5cb5b14610114578063a4d0c0a91461012f578063c3f909d414610142578063f2fde38b1461019657600080fd5b8063282c8749146100a3578063354662e0146100b85780633d23b9ca146100d357806343880d38146100e6578063715018a6146100f9575b600080fd5b6100b66100b1366004610dc6565b6101a9565b005b6100c06101ce565b6040519081526020015b60405180910390f35b6100c0686b656570657246656560b81b81565b6100c06100f4366004610e09565b61024f565b6100b6610ae7565b6100b661010f366004610e22565b610afb565b6000546040516001600160a01b0390911681526020016100ca565b6100b661013d366004610e59565b610b82565b600254600554600654600754600854600954600a54604080516001600160a01b0390981688526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016100ca565b6100b66101a4366004610e59565b610c10565b6101b1610c4e565b600595909555600693909355600791909155600855600955600a55565b600061024a600260009054906101000a90046001600160a01b03166001600160a01b0316636ef25c3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610226573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f49190610e76565b905090565b600080600080600080600160009054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156102ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102cf9190610eae565b509350509250507f00000000000000000000000000000000000000000000000000000000000004b0816103029190610f14565b421061032157604051631abf28d560e11b815260040160405180910390fd5b6000821361034257604051632702a96160e01b815260040160405180910390fd5b610351826402540be400610f27565b94506000600360009054906101000a90046001600160a01b03166001600160a01b031663779694666040518163ffffffff1660e01b81526004016040805180830381865afa1580156103a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cb9190610f52565b60035460408051634c6afee560e11b815281519395506001600160a01b0390921693506398d5fdca926004808401938290030181865afa158015610413573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104379190610f87565b909550935084610466576000604051630b1ba73960e21b815260040161045d9190610fab565b60405180910390fd5b61047663ffffffff821685610f14565b4210610498576000604051630c0ee27f60e31b815260040161045d9190610fab565b505050506000600260009054906101000a90046001600160a01b03166001600160a01b0316634ef6e2246040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561050d575060408051601f3d908101601f1916820190925261050a91810190610fd3565b60015b6105195750600061051c565b90505b6000811561081257600254604080516318b30b2360e31b8152905188926000926001600160a01b039091169163c5985918916004808201926020929091908290030181865afa158015610573573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105979190610ff5565b63ffffffff1690506000600260009054906101000a90046001600160a01b03166001600160a01b031663519b4bd36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106189190610e76565b90506000600260009054906101000a90046001600160a01b03166001600160a01b03166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa15801561066f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106939190610ff5565b63ffffffff1690506000600260009054906101000a90046001600160a01b03166001600160a01b031663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107149190610e76565b90506000600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561076b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078f9190610e76565b9050600061079e82600a6110f4565b6107a9906010610f27565b6107b38486610f27565b6107bd8789610f27565b6107c8906010610f27565b6107d29190610f14565b6107dc9190611116565b905086600a546107ec9190610f27565b816009546107fa9190610f27565b6108049190610f14565b975050505050505050610a51565b6002546040805163060c60b160e11b8152905188926000926001600160a01b0390911691630c18c162916004808201926020929091908290030181865afa158015610861573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108859190610e76565b90506000600260009054906101000a90046001600160a01b03166001600160a01b031663519b4bd36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109009190610e76565b90506000600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097b9190610e76565b90506000600260009054906101000a90046001600160a01b03166001600160a01b031663f45e65d86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f69190610e76565b905084600a54610a069190610f27565b610a1183600a6110f4565b828587600954610a219190610f14565b610a2b9190610f27565b610a359190610f27565b610a3f9190611116565b610a499190610f14565b955050505050505b6000610a668286670de0b6b3a7640000610c7b565b90506000610a95610a8c600654670de0b6b3a764000085610c7b9092919063ffffffff16565b60055490610d40565b90506000610aa38284610f14565b9050610ada670de0b6b3a764000087610ad3610aca60085486610d4090919063ffffffff16565b60075490610d5a565b9190610c7b565b9998505050505050505050565b610aef610c4e565b610af96000610d69565b565b610b03610c4e565b808211610b265760405163179c637760e11b81526004810182905260240161045d565b80600003610b775760405163046c82ad60e41b815260206004820152601360248201527f6b65657065724665654c6f776572426f756e6400000000000000000000000000604482015260640161045d565b600791909155600855565b610b8a610c4e565b6001600160a01b038116610be15760405163eac0d38960e01b815260206004820152600e60248201527f67617350726963654f7261636c65000000000000000000000000000000000000604482015260640161045d565b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b610c18610c4e565b6001600160a01b038116610c4257604051631e4fbdf760e01b81526000600482015260240161045d565b610c4b81610d69565b50565b6000546001600160a01b03163314610af95760405163118cdaa760e01b815233600482015260240161045d565b6000838302816000198587098281108382030391505080600003610cb257838281610ca857610ca8611100565b0492505050610d39565b808411610cd25760405163227bc15360e01b815260040160405180910390fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b6000818311610d4f5781610d51565b825b90505b92915050565b6000818310610d4f5781610d51565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060008060008060c08789031215610ddf57600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b600060208284031215610e1b57600080fd5b5035919050565b60008060408385031215610e3557600080fd5b50508035926020909101359150565b6001600160a01b0381168114610c4b57600080fd5b600060208284031215610e6b57600080fd5b8135610d3981610e44565b600060208284031215610e8857600080fd5b5051919050565b805169ffffffffffffffffffff81168114610ea957600080fd5b919050565b600080600080600060a08688031215610ec657600080fd5b610ecf86610e8f565b9450602086015193506040860151925060608601519150610ef260808701610e8f565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b80820180821115610d5457610d54610efe565b8082028115828204841417610d5457610d54610efe565b805163ffffffff81168114610ea957600080fd5b60008060408385031215610f6557600080fd5b8251610f7081610e44565b9150610f7e60208401610f3e565b90509250929050565b60008060408385031215610f9a57600080fd5b505080516020909101519092909150565b6020810160028310610fcd57634e487b7160e01b600052602160045260246000fd5b91905290565b600060208284031215610fe557600080fd5b81518015158114610d3957600080fd5b60006020828403121561100757600080fd5b610d5182610f3e565b600181815b8085111561104b57816000190482111561103157611031610efe565b8085161561103e57918102915b93841c9390800290611015565b509250929050565b60008261106257506001610d54565b8161106f57506000610d54565b8160018114611085576002811461108f576110ab565b6001915050610d54565b60ff8411156110a0576110a0610efe565b50506001821b610d54565b5060208310610133831016604e8410600b84101617156110ce575081810a610d54565b6110d88383611010565b80600019048211156110ec576110ec610efe565b029392505050565b6000610d518383611053565b634e487b7160e01b600052601260045260246000fd5b60008261113357634e487b7160e01b600052601260045260246000fd5b50049056fea26469706673582212204d5762bf5343af3efdb71903a20d1caa6f16d092a4e0bca7d8cacfef084d4dc664736f6c63430008140033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000001677640787891022efec86828bc386828c68d2aa00000000000000000000000071041dddad3595f9ced3dccfbe3d1f4b0a16bb70000000000000000000000000aba633927bd8622fbbdd35d291a914c2fdaae1ff000000000000000000000000b6fe221fe9eef5aba221c348ba20a1bf5e73624c00000000000000000000000000000000000000000000000006f05b59d3b200000000000000000000000000000000000000000000000000000429d069189e0000000000000000000000000000000000000000000000000001a055690d9db8000000000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000075300000000000000000000000000000000000000000000000000000000000124f8000000000000000000000000000000000000000000000000000000000000004b0

-----Decoded View---------------
Arg [0] : owner (address): 0x1677640787891022efEC86828BC386828c68d2aA
Arg [1] : ethOracle (address): 0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70
Arg [2] : oracleModule (address): 0xAba633927BD8622FBBDd35D291A914c2fDAaE1Ff
Arg [3] : assetToPayWith (address): 0xB6fe221Fe9EeF5aBa221c348bA20A1Bf5e73624c
Arg [4] : profitMarginUSD (uint256): 500000000000000000
Arg [5] : profitMarginPercent (uint256): 300000000000000000
Arg [6] : keeperFeeUpperBound (uint256): 30000000000000000000
Arg [7] : keeperFeeLowerBound (uint256): 500000000000000000
Arg [8] : gasUnitsL1 (uint256): 30000
Arg [9] : gasUnitsL2 (uint256): 1200000
Arg [10] : stalenessPeriod (uint256): 1200

-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000001677640787891022efec86828bc386828c68d2aa
Arg [1] : 00000000000000000000000071041dddad3595f9ced3dccfbe3d1f4b0a16bb70
Arg [2] : 000000000000000000000000aba633927bd8622fbbdd35d291a914c2fdaae1ff
Arg [3] : 000000000000000000000000b6fe221fe9eef5aba221c348ba20a1bf5e73624c
Arg [4] : 00000000000000000000000000000000000000000000000006f05b59d3b20000
Arg [5] : 0000000000000000000000000000000000000000000000000429d069189e0000
Arg [6] : 000000000000000000000000000000000000000000000001a055690d9db80000
Arg [7] : 00000000000000000000000000000000000000000000000006f05b59d3b20000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000007530
Arg [9] : 0000000000000000000000000000000000000000000000000000000000124f80
Arg [10] : 00000000000000000000000000000000000000000000000000000000000004b0


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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.