POL Price: $0.218737 (-0.57%)
Gas: 28.6 GWei
 

Overview

POL Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo6,985.398949165555201435 POL

POL Value

$1,527.96 (@ $0.22/POL)

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Metacall706486552025-04-23 8:37:201 min ago1745397440IN
0x4A394bD4...a3e0f32e0
0 POL0.0208946130.00000627
Metacall706486512025-04-23 8:37:121 min ago1745397432IN
0x4A394bD4...a3e0f32e0
0 POL0.0150704130
Unbond706486002025-04-23 8:35:243 mins ago1745397324IN
0x4A394bD4...a3e0f32e0
0 POL0.001353526.00000665
Metacall706485852025-04-23 8:34:523 mins ago1745397292IN
0x4A394bD4...a3e0f32e0
0 POL0.0170869230.00000579
Metacall706485842025-04-23 8:34:503 mins ago1745397290IN
0x4A394bD4...a3e0f32e0
0 POL0.0149897550.00000573
Metacall706485832025-04-23 8:34:483 mins ago1745397288IN
0x4A394bD4...a3e0f32e0
0 POL0.0202065989.32001407
Metacall706485822025-04-23 8:34:463 mins ago1745397286IN
0x4A394bD4...a3e0f32e0
0 POL0.0150057550.00000541
Metacall706485822025-04-23 8:34:463 mins ago1745397286IN
0x4A394bD4...a3e0f32e0
0 POL0.0113391550.00000541
Metacall706485822025-04-23 8:34:463 mins ago1745397286IN
0x4A394bD4...a3e0f32e0
0 POL0.038561866.55000542
Metacall706485822025-04-23 8:34:463 mins ago1745397286IN
0x4A394bD4...a3e0f32e0
0 POL0.0322206481.20000657
Metacall706485822025-04-23 8:34:463 mins ago1745397286IN
0x4A394bD4...a3e0f32e0
0 POL0.10164088128.76758245
Metacall706485822025-04-23 8:34:463 mins ago1745397286IN
0x4A394bD4...a3e0f32e0
0 POL0.07610114336.37500297
Metacall706485802025-04-23 8:34:423 mins ago1745397282IN
0x4A394bD4...a3e0f32e0
0 POL0.0178462830.00000551
Metacall706485552025-04-23 8:33:484 mins ago1745397228IN
0x4A394bD4...a3e0f32e0
0 POL0.0345028431.20000809
Withdraw706484872025-04-23 8:31:247 mins ago1745397084IN
0x4A394bD4...a3e0f32e0
0 POL0.0010776426.00000595
Metacall706484082025-04-23 8:28:3610 mins ago1745396916IN
0x4A394bD4...a3e0f32e0
0 POL0.0313753550
Unbond706484042025-04-23 8:28:2810 mins ago1745396908IN
0x4A394bD4...a3e0f32e0
0 POL0.001353526.00000523
Metacall706483792025-04-23 8:27:3411 mins ago1745396854IN
0x4A394bD4...a3e0f32e0
0 POL0.0380229133.80001002
Metacall706483562025-04-23 8:26:4611 mins ago1745396806IN
0x4A394bD4...a3e0f32e0
0 POL0.012539550.0000085
Metacall706483562025-04-23 8:26:4611 mins ago1745396806IN
0x4A394bD4...a3e0f32e0
0 POL0.0126223550.0000085
Metacall706483562025-04-23 8:26:4611 mins ago1745396806IN
0x4A394bD4...a3e0f32e0
0 POL0.0237985878.00002563
Metacall706483522025-04-23 8:26:3812 mins ago1745396798IN
0x4A394bD4...a3e0f32e0
0 POL0.0254374100.00000854
Metacall706483222025-04-23 8:25:3413 mins ago1745396734IN
0x4A394bD4...a3e0f32e0
0 POL0.0258327330.00000875
Withdraw706483182025-04-23 8:25:2413 mins ago1745396724IN
0x4A394bD4...a3e0f32e0
0 POL0.0010776426.00000813
Metacall706482742025-04-23 8:23:5214 mins ago1745396632IN
0x4A394bD4...a3e0f32e0
0 POL0.026345939.96679102
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
706486552025-04-23 8:37:201 min ago1745397440
0x4A394bD4...a3e0f32e0
0.03562789 POL
706486512025-04-23 8:37:121 min ago1745397432
0x4A394bD4...a3e0f32e0
0.02543508 POL
706485852025-04-23 8:34:523 mins ago1745397292
0x4A394bD4...a3e0f32e0
0.03085268 POL
706485802025-04-23 8:34:423 mins ago1745397282
0x4A394bD4...a3e0f32e0
0.03129097 POL
706485552025-04-23 8:33:484 mins ago1745397228
0x4A394bD4...a3e0f32e0
0.05555224 POL
706484872025-04-23 8:31:247 mins ago1745397084
0x4A394bD4...a3e0f32e0
0.32123078 POL
706483222025-04-23 8:25:3413 mins ago1745396734
0x4A394bD4...a3e0f32e0
0.04265715 POL
706483182025-04-23 8:25:2413 mins ago1745396724
0x4A394bD4...a3e0f32e0
0.44469399 POL
706482742025-04-23 8:23:5214 mins ago1745396632
0x4A394bD4...a3e0f32e0
0.04975212 POL
706482742025-04-23 8:23:5214 mins ago1745396632
0x4A394bD4...a3e0f32e0
0.05991784 POL
706482492025-04-23 8:22:5815 mins ago1745396578
0x4A394bD4...a3e0f32e0
0.05125271 POL
706482052025-04-23 8:21:2417 mins ago1745396484
0x4A394bD4...a3e0f32e0
0.05721141 POL
706480952025-04-23 8:17:3021 mins ago1745396250
0x4A394bD4...a3e0f32e0
0.05788286 POL
706480912025-04-23 8:17:2221 mins ago1745396242
0x4A394bD4...a3e0f32e0
0.03535197 POL
706480532025-04-23 8:16:0222 mins ago1745396162
0x4A394bD4...a3e0f32e0
0.06746149 POL
706480322025-04-23 8:15:1823 mins ago1745396118
0x4A394bD4...a3e0f32e0
0.03105051 POL
706479852025-04-23 8:13:3825 mins ago1745396018
0x4A394bD4...a3e0f32e0
0.05052889 POL
706479852025-04-23 8:13:3825 mins ago1745396018
0x4A394bD4...a3e0f32e0
0.07369295 POL
706479732025-04-23 8:13:1225 mins ago1745395992
0x4A394bD4...a3e0f32e0
0.04438845 POL
706479702025-04-23 8:13:0625 mins ago1745395986
0x4A394bD4...a3e0f32e0
0.03781394 POL
706479352025-04-23 8:11:5026 mins ago1745395910
0x4A394bD4...a3e0f32e0
0.02687026 POL
706479322025-04-23 8:11:4426 mins ago1745395904
0x4A394bD4...a3e0f32e0
0.23308004 POL
706479262025-04-23 8:11:3227 mins ago1745395892
0x4A394bD4...a3e0f32e0
0.04215249 POL
706479242025-04-23 8:11:2827 mins ago1745395888
0x4A394bD4...a3e0f32e0
0.02659976 POL
706478522025-04-23 8:08:5429 mins ago1745395734
0x4A394bD4...a3e0f32e0
0.20576437 POL
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Atlas

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 50 runs

Other Settings:
cancun EvmVersion
File 1 of 35 : Atlas.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol";
import { LibSort } from "solady/utils/LibSort.sol";

import { Escrow } from "./Escrow.sol";
import { Factory } from "./Factory.sol";

import "../types/SolverOperation.sol";
import "../types/UserOperation.sol";
import "../types/LockTypes.sol";
import "../types/ConfigTypes.sol";
import "../types/DAppOperation.sol";
import "../types/ValidCalls.sol";

import { CallBits } from "../libraries/CallBits.sol";
import { SafetyBits } from "../libraries/SafetyBits.sol";
import { IL2GasCalculator } from "../interfaces/IL2GasCalculator.sol";
import { IDAppControl } from "../interfaces/IDAppControl.sol";

/// @title Atlas V1.1
/// @author FastLane Labs
/// @notice The Execution Abstraction protocol.
contract Atlas is Escrow, Factory {
    using CallBits for uint32;
    using SafetyBits for Context;

    constructor(
        uint256 escrowDuration,
        uint256 atlasSurchargeRate,
        uint256 bundlerSurchargeRate,
        address verification,
        address simulator,
        address initialSurchargeRecipient,
        address l2GasCalculator,
        address factoryLib
    )
        Escrow(
            escrowDuration,
            atlasSurchargeRate,
            bundlerSurchargeRate,
            verification,
            simulator,
            initialSurchargeRecipient,
            l2GasCalculator
        )
        Factory(factoryLib)
    { }

    /// @notice metacall is the entrypoint function for the Atlas transactions.
    /// @dev Any ETH sent as msg.value with a metacall should be considered a potential subsidy for the winning solver's
    /// gas repayment.
    /// @param userOp The UserOperation struct containing the user's transaction data.
    /// @param solverOps The SolverOperation array containing the solvers' transaction data.
    /// @param dAppOp The DAppOperation struct containing the DApp's transaction data.
    /// @param gasRefundBeneficiary The address to receive the gas refund.
    /// @return auctionWon A boolean indicating whether there was a successful, winning solver.
    function metacall(
        UserOperation calldata userOp, // set by user
        SolverOperation[] calldata solverOps, // supplied by ops relay
        DAppOperation calldata dAppOp, // supplied by front end via atlas SDK
        address gasRefundBeneficiary // address(0) = msg.sender
    )
        external
        payable
        returns (bool auctionWon)
    {
        uint256 _gasMarker = L2_GAS_CALCULATOR == address(0)
            ? gasleft() + _BASE_TRANSACTION_GAS_USED + (msg.data.length * _CALLDATA_LENGTH_PREMIUM_HALVED)
            : gasleft() + IL2GasCalculator(L2_GAS_CALCULATOR).initialGasUsed(msg.data.length);

        bool _isSimulation = msg.sender == SIMULATOR;
        address _bundler = _isSimulation ? dAppOp.bundler : msg.sender;
        (address _executionEnvironment, DAppConfig memory _dConfig) = _getOrCreateExecutionEnvironment(userOp);

        {
            ValidCallsResult _validCallsResult =
                VERIFICATION.validateCalls(_dConfig, userOp, solverOps, dAppOp, msg.value, _bundler, _isSimulation);
            if (_validCallsResult != ValidCallsResult.Valid) {
                if (_isSimulation) revert VerificationSimFail(_validCallsResult);

                // Gracefully return for results that need nonces to be stored and prevent replay attacks
                if (uint8(_validCallsResult) >= _GRACEFUL_RETURN_THRESHOLD && !_dConfig.callConfig.allowsReuseUserOps())
                {
                    return false;
                }

                // Revert for all other results
                revert ValidCalls(_validCallsResult);
            }
        }

        // Initialize the environment lock and accounting values
        _setEnvironmentLock(_dConfig, _executionEnvironment);
        _initializeAccountingValues(_gasMarker);

        // userOpHash has already been calculated and verified in validateCalls at this point, so rather
        // than re-calculate it, we can simply take it from the dAppOp here. It's worth noting that this will
        // be either a TRUSTED or DEFAULT hash, depending on the allowsTrustedOpHash setting.
        try this.execute(_dConfig, userOp, solverOps, _executionEnvironment, _bundler, dAppOp.userOpHash, _isSimulation)
        returns (Context memory ctx) {
            // Gas Refund to sender only if execution is successful
            (uint256 _ethPaidToBundler, uint256 _netGasSurcharge) =
                _settle(ctx, _dConfig.solverGasLimit, gasRefundBeneficiary);

            auctionWon = ctx.solverSuccessful;
            emit MetacallResult(
                msg.sender, userOp.from, auctionWon, ctx.paymentsSuccessful, _ethPaidToBundler, _netGasSurcharge
            );
        } catch (bytes memory revertData) {
            // Bubble up some specific errors
            _handleErrors(revertData, _dConfig.callConfig);
            // Set lock to FullyLocked to prevent any reentrancy possibility
            _setLockPhase(uint8(ExecutionPhase.FullyLocked));

            // Refund the msg.value to sender if it errored
            // WARNING: If msg.sender is a disposable address such as a session key, make sure to remove ETH from it
            // before disposal
            if (msg.value != 0) SafeTransferLib.safeTransferETH(msg.sender, msg.value);

            // Emit event indicating the metacall failed in `execute()`
            emit MetacallResult(msg.sender, userOp.from, false, false, 0, 0);
        }

        // The environment lock is explicitly released here to allow multiple metacalls in a single transaction.
        _releaseLock();
    }

    /// @notice execute is called above, in a try-catch block in metacall.
    /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings.
    /// @param userOp UserOperation struct of the current metacall tx.
    /// @param solverOps SolverOperation array of the current metacall tx.
    /// @param executionEnvironment Address of the execution environment contract of the current metacall tx.
    /// @param bundler Address of the bundler of the current metacall tx.
    /// @param userOpHash Hash of the userOp struct of the current metacall tx.
    /// @return ctx Context struct containing relevant context information for the Atlas auction.
    function execute(
        DAppConfig memory dConfig,
        UserOperation calldata userOp,
        SolverOperation[] calldata solverOps,
        address executionEnvironment,
        address bundler,
        bytes32 userOpHash,
        bool isSimulation
    )
        external
        payable
        returns (Context memory ctx)
    {
        // This is a self.call made externally so that it can be used with try/catch
        if (msg.sender != address(this)) revert InvalidAccess();

        // Build the context object
        ctx = _buildContext(executionEnvironment, userOpHash, bundler, uint8(solverOps.length), isSimulation);

        bytes memory _returnData;

        // PreOps Call
        if (dConfig.callConfig.needsPreOpsCall()) {
            _returnData = _executePreOpsCall(ctx, dConfig, userOp);
        }

        // UserOp Call
        _returnData = _executeUserOperation(ctx, dConfig, userOp, _returnData);

        // SolverOps Calls
        uint256 _winningBidAmount = dConfig.callConfig.exPostBids()
            ? _bidFindingIteration(ctx, dConfig, userOp, solverOps, _returnData)
            : _bidKnownIteration(ctx, dConfig, userOp, solverOps, _returnData);

        // AllocateValue Call
        if (ctx.solverSuccessful) {
            _allocateValue(ctx, dConfig, _winningBidAmount, _returnData);
        }

        // PostOp Call
        if (dConfig.callConfig.needsPostOpsCall()) {
            _executePostOpsCall(ctx, ctx.solverSuccessful, _returnData);
        }
    }

    /// @notice Called above in `execute` if the DAppConfig requires ex post bids. Sorts solverOps by bid amount and
    /// executes them in descending order until a successful winner is found.
    /// @param ctx Context struct containing the current state of the escrow lock.
    /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings.
    /// @param userOp UserOperation struct of the current metacall tx.
    /// @param solverOps SolverOperation array of the current metacall tx.
    /// @param returnData Return data from the preOps and userOp calls.
    /// @return The winning bid amount or 0 when no solverOps.
    function _bidFindingIteration(
        Context memory ctx,
        DAppConfig memory dConfig,
        UserOperation calldata userOp,
        SolverOperation[] calldata solverOps,
        bytes memory returnData
    )
        internal
        returns (uint256)
    {
        uint256 solverOpsLength = solverOps.length; // computed once for efficiency

        // Return early if no solverOps (e.g. in simUserOperation)
        if (solverOpsLength == 0) {
            if (ctx.isSimulation) revert SolverSimFail(0);
            if (dConfig.callConfig.needsFulfillment()) revert UserNotFulfilled();
            return 0;
        }

        ctx.bidFind = true;

        uint256[] memory _bidsAndIndices = new uint256[](solverOpsLength);
        uint256 _bidAmountFound;
        uint256 _bidsAndIndicesLastIndex = solverOpsLength - 1; // Start from the last index
        uint256 _gasWaterMark = gasleft();

        // First, get all bid amounts. Bids of zero are ignored by only storing non-zero bids in the array, from right
        // to left. If there are any zero bids they will end up on the left as uint(0) values - in their sorted
        // position. This reduces operations needed later when sorting the array in ascending order.
        // Each non-zero bid amount is packed with its original solverOps array index, to fit into a uint256 value. The
        // order of bidAmount and index is important - with bidAmount using the most significant bits, and considering
        // we do not store zero bids in the array, the index values within the uint256 should not impact the sorting.

        // |<------------------------- uint256 (256 bits) ------------------------->|
        // |                                                                        |
        // |<------------------ uint240 ----------------->|<-------- uint16 ------->|
        // |                                              |                         |
        // |                    bidAmount                 |          index          |
        // |                                              |                         |
        // |<------------------ 240 bits ---------------->|<------- 16 bits ------->|

        for (uint256 i; i < solverOpsLength; ++i) {
            _bidAmountFound = _getBidAmount(ctx, dConfig, userOp, solverOps[i], returnData);

            // skip zero and overflow bid's
            if (_bidAmountFound != 0 && _bidAmountFound <= type(uint240).max) {
                // Non-zero bids are packed with their original solverOps index.
                // The array is filled with non-zero bids from the right.
                _bidsAndIndices[_bidsAndIndicesLastIndex] = uint256(_bidAmountFound << _BITS_FOR_INDEX | uint16(i));
                unchecked {
                    --_bidsAndIndicesLastIndex;
                }
            }
        }

        // Reinitialize _bidsAndIndicesLastIndex to iterate through the sorted array in descending order
        _bidsAndIndicesLastIndex = solverOpsLength - 1;

        // Then, sorts the uint256 array in-place, in ascending order.
        LibSort.insertionSort(_bidsAndIndices);

        ctx.bidFind = false;

        // Write off the gas cost involved in on-chain bid-finding execution of all solverOps, as these costs should be
        // paid by the bundler.
        _writeOffBidFindGasCost(_gasWaterMark - gasleft());

        // Finally, iterate through sorted bidsAndIndices array in descending order of bidAmount.
        for (uint256 i = _bidsAndIndicesLastIndex;; /* breaks when 0 */ --i) {
            // Isolate the bidAmount from the packed uint256 value
            _bidAmountFound = _bidsAndIndices[i] >> _BITS_FOR_INDEX;

            // If we reach the zero bids on the left of array, break as all valid bids already checked.
            if (_bidAmountFound == 0) break;

            // NOTE: We reuse the ctx.solverIndex variable to store the count of solver ops that have been executed.
            // This count is useful in `_settle()` when we may penalize the bundler for overestimating gas limit of the
            // metacall tx.
            ctx.solverIndex = uint8(_bidsAndIndicesLastIndex - i);

            // Isolate the original solverOps index from the packed uint256 value
            uint256 _solverIndex = uint8(_bidsAndIndices[i] & _FIRST_16_BITS_TRUE_MASK);

            // Execute the solver operation. If solver won, allocate value and return. Otherwise continue looping.
            _bidAmountFound = _executeSolverOperation(
                ctx, dConfig, userOp, solverOps[_solverIndex], _bidAmountFound, true, returnData
            );

            if (ctx.solverSuccessful) {
                return _bidAmountFound;
            }

            if (i == 0) break; // break to prevent underflow in next loop
        }
        if (ctx.isSimulation) revert SolverSimFail(uint256(ctx.solverOutcome));
        if (dConfig.callConfig.needsFulfillment()) revert UserNotFulfilled();
        return 0;
    }

    /// @notice Called above in `execute` as an alternative to `_bidFindingIteration`, if solverOps have already been
    /// reliably sorted. Executes solverOps in order until a successful winner is found.
    /// @param ctx Context struct containing the current state of the escrow lock.
    /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings.
    /// @param userOp UserOperation struct of the current metacall tx.
    /// @param solverOps SolverOperation array of the current metacall tx.
    /// @param returnData Return data from the preOps and userOp calls.
    /// @return The winning bid amount or 0 when no solverOps.
    function _bidKnownIteration(
        Context memory ctx,
        DAppConfig memory dConfig,
        UserOperation calldata userOp,
        SolverOperation[] calldata solverOps,
        bytes memory returnData
    )
        internal
        returns (uint256)
    {
        uint256 _bidAmount;

        uint8 i = uint8(solverOps.length);
        for (; ctx.solverIndex < i; ctx.solverIndex++) {
            SolverOperation calldata solverOp = solverOps[ctx.solverIndex];

            _bidAmount = _executeSolverOperation(ctx, dConfig, userOp, solverOp, solverOp.bidAmount, false, returnData);

            if (ctx.solverSuccessful) {
                return _bidAmount;
            }
        }
        if (ctx.isSimulation) revert SolverSimFail(uint256(ctx.solverOutcome));
        if (dConfig.callConfig.needsFulfillment()) revert UserNotFulfilled();
        return 0;
    }

    /// @notice Called at the end of `metacall` to bubble up specific error info in a revert.
    /// @param revertData Revert data from a failure during the execution of the metacall.
    /// @param callConfig The CallConfig of the current metacall tx.
    function _handleErrors(bytes memory revertData, uint32 callConfig) internal view {
        bytes4 _errorSwitch = bytes4(revertData);

        if (msg.sender == SIMULATOR) {
            if (_errorSwitch == SolverSimFail.selector) {
                // Expects revertData in form [bytes4, uint256]
                uint256 _solverOutcomeResult;
                assembly {
                    let dataLocation := add(revertData, 0x20)
                    _solverOutcomeResult := mload(add(dataLocation, sub(mload(revertData), 32)))
                }
                revert SolverSimFail(_solverOutcomeResult);
            } else if (
                _errorSwitch == PreOpsSimFail.selector || _errorSwitch == UserOpSimFail.selector
                    || _errorSwitch == AllocateValueSimFail.selector || _errorSwitch == PostOpsSimFail.selector
            ) {
                assembly {
                    mstore(0, _errorSwitch)
                    revert(0, 4)
                }
            }
        }

        // NOTE: If error was UserNotFulfilled, we revert and bubble up the error.
        // For any other error, we only bubble up the revert if allowReuseUserOps = true. This is to prevent storing the
        // nonce as used so the userOp can be reused. Otherwise, the whole metacall doesn't revert but the inner
        // execute() does so, no operation changes are persisted.
        if (_errorSwitch == UserNotFulfilled.selector || callConfig.allowsReuseUserOps()) {
            assembly {
                mstore(0, _errorSwitch)
                revert(0, 4)
            }
        }
    }

    /// @notice Returns whether or not the execution environment address matches what's expected from the set of inputs.
    /// @param environment ExecutionEnvironment address
    /// @param user User address
    /// @param control DAppControl contract address
    /// @param callConfig CallConfig of the current metacall tx.
    /// @return A bool indicating whether the execution environment address is the same address that the factory would
    /// deploy an Execution Environment to, given the user, control, and callConfig params.
    function _verifyUserControlExecutionEnv(
        address environment,
        address user,
        address control,
        uint32 callConfig
    )
        internal
        override
        returns (bool)
    {
        return environment == _getExecutionEnvironmentCustom(user, control, callConfig);
    }
}

File 2 of 35 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /// @dev The Permit2 operation has failed.
    error Permit2Failed();

    /// @dev The Permit2 amount must be less than `2**160 - 1`.
    error Permit2AmountOverflow();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /// @dev The unique EIP-712 domain domain separator for the DAI token contract.
    bytes32 internal constant DAI_DOMAIN_SEPARATOR =
        0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;

    /// @dev The address for the WETH9 contract on Ethereum mainnet.
    address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    /// @dev The canonical Permit2 address.
    /// [Github](https://github.com/Uniswap/permit2)
    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
    address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function trySafeTransferFrom(address token, address from, address to, uint256 amount)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            success :=
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                mstore(0x34, amount) // Store back the original `amount`.
                // Retry the approval, reverting upon failure.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul( // The arguments of `mul` are evaluated from right to left.
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// If the initial attempt fails, try to use Permit2 to transfer the token.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
        if (!trySafeTransferFrom(token, from, to, amount)) {
            permit2TransferFrom(token, from, to, amount);
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.
    /// Reverts upon failure.
    function permit2TransferFrom(address token, address from, address to, uint256 amount)
        internal
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(add(m, 0x74), shr(96, shl(96, token)))
            mstore(add(m, 0x54), amount)
            mstore(add(m, 0x34), to)
            mstore(add(m, 0x20), shl(96, from))
            // `transferFrom(address,address,uint160,address)`.
            mstore(m, 0x36c78516000000000000000000000000)
            let p := PERMIT2
            let exists := eq(chainid(), 1)
            if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
            if iszero(and(call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00), exists)) {
                mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
            }
        }
    }

    /// @dev Permit a user to spend a given amount of
    /// another user's tokens via native EIP-2612 permit if possible, falling
    /// back to Permit2 if native permit fails or is not implemented on the token.
    function permit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        bool success;
        /// @solidity memory-safe-assembly
        assembly {
            for {} shl(96, xor(token, WETH9)) {} {
                mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.
                if iszero(
                    and( // The arguments of `and` are evaluated from right to left.
                        lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.
                        // Gas stipend to limit gas burn for tokens that don't refund gas when
                        // an non-existing function is called. 5K should be enough for a SLOAD.
                        staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
                    )
                ) { break }
                // After here, we can be sure that token is a contract.
                let m := mload(0x40)
                mstore(add(m, 0x34), spender)
                mstore(add(m, 0x20), shl(96, owner))
                mstore(add(m, 0x74), deadline)
                if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
                    mstore(0x14, owner)
                    mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.
                    mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
                    mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
                    // `nonces` is already at `add(m, 0x54)`.
                    // `1` is already stored at `add(m, 0x94)`.
                    mstore(add(m, 0xb4), and(0xff, v))
                    mstore(add(m, 0xd4), r)
                    mstore(add(m, 0xf4), s)
                    success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
                    break
                }
                mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.
                mstore(add(m, 0x54), amount)
                mstore(add(m, 0x94), and(0xff, v))
                mstore(add(m, 0xb4), r)
                mstore(add(m, 0xd4), s)
                success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
                break
            }
        }
        if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
    }

    /// @dev Simple permit on the Permit2 contract.
    function simplePermit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, 0x927da105) // `allowance(address,address,address)`.
            {
                let addressMask := shr(96, not(0))
                mstore(add(m, 0x20), and(addressMask, owner))
                mstore(add(m, 0x40), and(addressMask, token))
                mstore(add(m, 0x60), and(addressMask, spender))
                mstore(add(m, 0xc0), and(addressMask, spender))
            }
            let p := mul(PERMIT2, iszero(shr(160, amount)))
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.
                    staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
                )
            ) {
                mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(p))), 0x04)
            }
            mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).
            // `owner` is already `add(m, 0x20)`.
            // `token` is already at `add(m, 0x40)`.
            mstore(add(m, 0x60), amount)
            mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.
            // `nonce` is already at `add(m, 0xa0)`.
            // `spender` is already at `add(m, 0xc0)`.
            mstore(add(m, 0xe0), deadline)
            mstore(add(m, 0x100), 0x100) // `signature` offset.
            mstore(add(m, 0x120), 0x41) // `signature` length.
            mstore(add(m, 0x140), r)
            mstore(add(m, 0x160), s)
            mstore(add(m, 0x180), shl(248, v))
            if iszero(call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00)) {
                mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

File 3 of 35 : LibSort.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Optimized sorts and operations for sorted arrays.
/// @author Solady (https://github.com/Vectorized/solady/blob/main/src/utils/LibSort.sol)
library LibSort {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      INSERTION SORT                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // - Faster on small arrays (32 or lesser elements).
    // - Faster on almost sorted arrays.
    // - Smaller bytecode.
    // - May be suitable for view functions intended for off-chain querying.

    /// @dev Sorts the array in-place with insertion sort.
    function insertionSort(uint256[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(a) // Length of `a`.
            mstore(a, 0) // For insertion sort's inner loop to terminate.
            let h := add(a, shl(5, n)) // High slot.
            let w := not(0x1f)
            for { let i := add(a, 0x20) } 1 {} {
                i := add(i, 0x20)
                if gt(i, h) { break }
                let k := mload(i) // Key.
                let j := add(i, w) // The slot before the current slot.
                let v := mload(j) // The value of `j`.
                if iszero(gt(v, k)) { continue }
                for {} 1 {} {
                    mstore(add(j, 0x20), v)
                    j := add(j, w) // `sub(j, 0x20)`.
                    v := mload(j)
                    if iszero(gt(v, k)) { break }
                }
                mstore(add(j, 0x20), k)
            }
            mstore(a, n) // Restore the length of `a`.
        }
    }

    /// @dev Sorts the array in-place with insertion sort.
    function insertionSort(int256[] memory a) internal pure {
        _flipSign(a);
        insertionSort(_toUints(a));
        _flipSign(a);
    }

    /// @dev Sorts the array in-place with insertion sort.
    function insertionSort(address[] memory a) internal pure {
        insertionSort(_toUints(a));
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      INTRO-QUICKSORT                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // - Faster on larger arrays (more than 32 elements).
    // - Robust performance.
    // - Larger bytecode.

    /// @dev Sorts the array in-place with intro-quicksort.
    function sort(uint256[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            function swap(a_, b_) -> _a, _b {
                _b := a_
                _a := b_
            }
            function mswap(i_, j_) {
                let t_ := mload(i_)
                mstore(i_, mload(j_))
                mstore(j_, t_)
            }
            function sortInner(w_, l_, h_) {
                // Do insertion sort if `h_ - l_ <= 0x20 * 12`.
                // Threshold is fine-tuned via trial and error.
                if iszero(gt(sub(h_, l_), 0x180)) {
                    // Hardcode sort the first 2 elements.
                    let i_ := add(l_, 0x20)
                    if iszero(lt(mload(l_), mload(i_))) { mswap(i_, l_) }
                    for {} 1 {} {
                        i_ := add(i_, 0x20)
                        if gt(i_, h_) { break }
                        let k_ := mload(i_) // Key.
                        let j_ := add(i_, w_) // The slot before the current slot.
                        let v_ := mload(j_) // The value of `j_`.
                        if iszero(gt(v_, k_)) { continue }
                        for {} 1 {} {
                            mstore(add(j_, 0x20), v_)
                            j_ := add(j_, w_)
                            v_ := mload(j_)
                            if iszero(gt(v_, k_)) { break }
                        }
                        mstore(add(j_, 0x20), k_)
                    }
                    leave
                }
                // Pivot slot is the average of `l_` and `h_`.
                let p_ := add(shl(5, shr(6, add(l_, h_))), and(31, l_))
                // Median of 3 with sorting.
                {
                    let e0_ := mload(l_)
                    let e1_ := mload(p_)
                    if iszero(lt(e0_, e1_)) { e0_, e1_ := swap(e0_, e1_) }
                    let e2_ := mload(h_)
                    if iszero(lt(e1_, e2_)) {
                        e1_, e2_ := swap(e1_, e2_)
                        if iszero(lt(e0_, e1_)) { e0_, e1_ := swap(e0_, e1_) }
                    }
                    mstore(h_, e2_)
                    mstore(p_, e1_)
                    mstore(l_, e0_)
                }
                // Hoare's partition.
                {
                    // The value of the pivot slot.
                    let x_ := mload(p_)
                    p_ := h_
                    for { let i_ := l_ } 1 {} {
                        for {} 1 {} {
                            i_ := add(0x20, i_)
                            if iszero(gt(x_, mload(i_))) { break }
                        }
                        let j_ := p_
                        for {} 1 {} {
                            j_ := add(w_, j_)
                            if iszero(lt(x_, mload(j_))) { break }
                        }
                        p_ := j_
                        if iszero(lt(i_, p_)) { break }
                        mswap(i_, p_)
                    }
                }
                if iszero(eq(add(p_, 0x20), h_)) { sortInner(w_, add(p_, 0x20), h_) }
                if iszero(eq(p_, l_)) { sortInner(w_, l_, p_) }
            }

            for { let n := mload(a) } iszero(lt(n, 2)) {} {
                let w := not(0x1f) // `-0x20`.
                let l := add(a, 0x20) // Low slot.
                let h := add(a, shl(5, n)) // High slot.
                let j := h
                // While `mload(j - 0x20) <= mload(j): j -= 0x20`.
                for {} iszero(gt(mload(add(w, j)), mload(j))) {} { j := add(w, j) }
                // If the array is already sorted, break.
                if iszero(gt(j, l)) { break }
                // While `mload(j - 0x20) >= mload(j): j -= 0x20`.
                for { j := h } iszero(lt(mload(add(w, j)), mload(j))) {} { j := add(w, j) }
                // If the array is reversed sorted.
                if iszero(gt(j, l)) {
                    for {} 1 {} {
                        let t := mload(l)
                        mstore(l, mload(h))
                        mstore(h, t)
                        h := add(w, h)
                        l := add(l, 0x20)
                        if iszero(lt(l, h)) { break }
                    }
                    break
                }
                mstore(a, 0) // For insertion sort's inner loop to terminate.
                sortInner(w, l, h)
                mstore(a, n) // Restore the length of `a`.
                break
            }
        }
    }

    /// @dev Sorts the array in-place with intro-quicksort.
    function sort(int256[] memory a) internal pure {
        _flipSign(a);
        sort(_toUints(a));
        _flipSign(a);
    }

    /// @dev Sorts the array in-place with intro-quicksort.
    function sort(address[] memory a) internal pure {
        sort(_toUints(a));
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  OTHER USEFUL OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // For performance, the `uniquifySorted` methods will not revert if the
    // array is not sorted -- it will simply remove consecutive duplicate elements.

    /// @dev Removes duplicate elements from a ascendingly sorted memory array.
    function uniquifySorted(uint256[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            // If the length of `a` is greater than 1.
            if iszero(lt(mload(a), 2)) {
                let x := add(a, 0x20)
                let y := add(a, 0x40)
                let end := add(a, shl(5, add(mload(a), 1)))
                for {} 1 {} {
                    if iszero(eq(mload(x), mload(y))) {
                        x := add(x, 0x20)
                        mstore(x, mload(y))
                    }
                    y := add(y, 0x20)
                    if eq(y, end) { break }
                }
                mstore(a, shr(5, sub(x, a)))
            }
        }
    }

    /// @dev Removes duplicate elements from a ascendingly sorted memory array.
    function uniquifySorted(int256[] memory a) internal pure {
        uniquifySorted(_toUints(a));
    }

    /// @dev Removes duplicate elements from a ascendingly sorted memory array.
    function uniquifySorted(address[] memory a) internal pure {
        uniquifySorted(_toUints(a));
    }

    /// @dev Returns whether `a` contains `needle`, and the index of `needle`.
    /// `index` precedence: equal to > nearest before > nearest after.
    function searchSorted(uint256[] memory a, uint256 needle)
        internal
        pure
        returns (bool found, uint256 index)
    {
        (found, index) = _searchSorted(a, needle, 0);
    }

    /// @dev Returns whether `a` contains `needle`, and the index of `needle`.
    /// `index` precedence: equal to > nearest before > nearest after.
    function searchSorted(int256[] memory a, int256 needle)
        internal
        pure
        returns (bool found, uint256 index)
    {
        (found, index) = _searchSorted(_toUints(a), uint256(needle), 1 << 255);
    }

    /// @dev Returns whether `a` contains `needle`, and the index of `needle`.
    /// `index` precedence: equal to > nearest before > nearest after.
    function searchSorted(address[] memory a, address needle)
        internal
        pure
        returns (bool found, uint256 index)
    {
        (found, index) = _searchSorted(_toUints(a), uint256(uint160(needle)), 0);
    }

    /// @dev Reverses the array in-place.
    function reverse(uint256[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(lt(mload(a), 2)) {
                let s := 0x20
                let w := not(0x1f)
                let h := add(a, shl(5, mload(a)))
                for { a := add(a, s) } 1 {} {
                    let t := mload(a)
                    mstore(a, mload(h))
                    mstore(h, t)
                    h := add(h, w)
                    a := add(a, s)
                    if iszero(lt(a, h)) { break }
                }
            }
        }
    }

    /// @dev Reverses the array in-place.
    function reverse(int256[] memory a) internal pure {
        reverse(_toUints(a));
    }

    /// @dev Reverses the array in-place.
    function reverse(address[] memory a) internal pure {
        reverse(_toUints(a));
    }

    /// @dev Returns a copy of the array.
    function copy(uint256[] memory a) internal pure returns (uint256[] memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let end := add(add(result, 0x20), shl(5, mload(a)))
            let o := result
            for { let d := sub(a, result) } 1 {} {
                mstore(o, mload(add(o, d)))
                o := add(0x20, o)
                if eq(o, end) { break }
            }
            mstore(0x40, o)
        }
    }

    /// @dev Returns a copy of the array.
    function copy(int256[] memory a) internal pure returns (int256[] memory result) {
        result = _toInts(copy(_toUints(a)));
    }

    /// @dev Returns a copy of the array.
    function copy(address[] memory a) internal pure returns (address[] memory result) {
        result = _toAddresses(copy(_toUints(a)));
    }

    /// @dev Returns whether the array is sorted in ascending order.
    function isSorted(uint256[] memory a) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if iszero(lt(mload(a), 2)) {
                let end := add(a, shl(5, mload(a)))
                for { a := add(a, 0x20) } 1 {} {
                    let p := mload(a)
                    a := add(a, 0x20)
                    result := iszero(gt(p, mload(a)))
                    if iszero(mul(result, xor(a, end))) { break }
                }
            }
        }
    }

    /// @dev Returns whether the array is sorted in ascending order.
    function isSorted(int256[] memory a) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if iszero(lt(mload(a), 2)) {
                let end := add(a, shl(5, mload(a)))
                for { a := add(a, 0x20) } 1 {} {
                    let p := mload(a)
                    a := add(a, 0x20)
                    result := iszero(sgt(p, mload(a)))
                    if iszero(mul(result, xor(a, end))) { break }
                }
            }
        }
    }

    /// @dev Returns whether the array is sorted in ascending order.
    function isSorted(address[] memory a) internal pure returns (bool result) {
        result = isSorted(_toUints(a));
    }

    /// @dev Returns whether the array is strictly ascending (sorted and uniquified).
    function isSortedAndUniquified(uint256[] memory a) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if iszero(lt(mload(a), 2)) {
                let end := add(a, shl(5, mload(a)))
                for { a := add(a, 0x20) } 1 {} {
                    let p := mload(a)
                    a := add(a, 0x20)
                    result := lt(p, mload(a))
                    if iszero(mul(result, xor(a, end))) { break }
                }
            }
        }
    }

    /// @dev Returns whether the array is strictly ascending (sorted and uniquified).
    function isSortedAndUniquified(int256[] memory a) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if iszero(lt(mload(a), 2)) {
                let end := add(a, shl(5, mload(a)))
                for { a := add(a, 0x20) } 1 {} {
                    let p := mload(a)
                    a := add(a, 0x20)
                    result := slt(p, mload(a))
                    if iszero(mul(result, xor(a, end))) { break }
                }
            }
        }
    }

    /// @dev Returns whether the array is strictly ascending (sorted and uniquified).
    function isSortedAndUniquified(address[] memory a) internal pure returns (bool result) {
        result = isSortedAndUniquified(_toUints(a));
    }

    /// @dev Returns the sorted set difference of `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function difference(uint256[] memory a, uint256[] memory b)
        internal
        pure
        returns (uint256[] memory c)
    {
        c = _difference(a, b, 0);
    }

    /// @dev Returns the sorted set difference between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function difference(int256[] memory a, int256[] memory b)
        internal
        pure
        returns (int256[] memory c)
    {
        c = _toInts(_difference(_toUints(a), _toUints(b), 1 << 255));
    }

    /// @dev Returns the sorted set difference between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function difference(address[] memory a, address[] memory b)
        internal
        pure
        returns (address[] memory c)
    {
        c = _toAddresses(_difference(_toUints(a), _toUints(b), 0));
    }

    /// @dev Returns the sorted set intersection between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function intersection(uint256[] memory a, uint256[] memory b)
        internal
        pure
        returns (uint256[] memory c)
    {
        c = _intersection(a, b, 0);
    }

    /// @dev Returns the sorted set intersection between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function intersection(int256[] memory a, int256[] memory b)
        internal
        pure
        returns (int256[] memory c)
    {
        c = _toInts(_intersection(_toUints(a), _toUints(b), 1 << 255));
    }

    /// @dev Returns the sorted set intersection between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function intersection(address[] memory a, address[] memory b)
        internal
        pure
        returns (address[] memory c)
    {
        c = _toAddresses(_intersection(_toUints(a), _toUints(b), 0));
    }

    /// @dev Returns the sorted set union of `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function union(uint256[] memory a, uint256[] memory b)
        internal
        pure
        returns (uint256[] memory c)
    {
        c = _union(a, b, 0);
    }

    /// @dev Returns the sorted set union of `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function union(int256[] memory a, int256[] memory b)
        internal
        pure
        returns (int256[] memory c)
    {
        c = _toInts(_union(_toUints(a), _toUints(b), 1 << 255));
    }

    /// @dev Returns the sorted set union between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function union(address[] memory a, address[] memory b)
        internal
        pure
        returns (address[] memory c)
    {
        c = _toAddresses(_union(_toUints(a), _toUints(b), 0));
    }

    /// @dev Cleans the upper 96 bits of the addresses.
    /// In case `a` is produced via assembly and might have dirty upper bits.
    function clean(address[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let addressMask := shr(96, not(0))
            for { let end := add(a, shl(5, mload(a))) } iszero(eq(a, end)) {} {
                a := add(a, 0x20)
                mstore(a, and(mload(a), addressMask))
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Reinterpret cast to an uint256 array.
    function _toUints(int256[] memory a) private pure returns (uint256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            casted := a
        }
    }

    /// @dev Reinterpret cast to an uint256 array.
    function _toUints(address[] memory a) private pure returns (uint256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            // As any address written to memory will have the upper 96 bits
            // of the word zeroized (as per Solidity spec), we can directly
            // compare these addresses as if they are whole uint256 words.
            casted := a
        }
    }

    /// @dev Reinterpret cast to an int array.
    function _toInts(uint256[] memory a) private pure returns (int256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            casted := a
        }
    }

    /// @dev Reinterpret cast to an address array.
    function _toAddresses(uint256[] memory a) private pure returns (address[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            casted := a
        }
    }

    /// @dev Converts an array of signed integers to unsigned
    /// integers suitable for sorting or vice versa.
    function _flipSign(int256[] memory a) private pure {
        /// @solidity memory-safe-assembly
        assembly {
            let w := shl(255, 1)
            for { let end := add(a, shl(5, mload(a))) } iszero(eq(a, end)) {} {
                a := add(a, 0x20)
                mstore(a, add(mload(a), w))
            }
        }
    }

    /// @dev Returns whether `a` contains `needle`, and the index of `needle`.
    /// `index` precedence: equal to > nearest before > nearest after.
    function _searchSorted(uint256[] memory a, uint256 needle, uint256 signed)
        private
        pure
        returns (bool found, uint256 index)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(0)
            let l := 1
            let h := mload(a)
            let t := 0
            for { needle := add(signed, needle) } 1 {} {
                index := shr(1, add(l, h))
                t := add(signed, mload(add(a, shl(5, index))))
                if or(gt(l, h), eq(t, needle)) { break }
                // Decide whether to search the left or right half.
                if iszero(gt(needle, t)) {
                    h := add(index, w)
                    continue
                }
                l := add(index, 1)
            }
            // `index` will be zero in the case of an empty array,
            // or when the value is less than the smallest value in the array.
            found := eq(t, needle)
            t := iszero(iszero(index))
            index := mul(add(index, w), t)
            found := and(found, t)
        }
    }

    /// @dev Returns the sorted set difference of `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function _difference(uint256[] memory a, uint256[] memory b, uint256 signed)
        private
        pure
        returns (uint256[] memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let s := 0x20
            let aEnd := add(a, shl(5, mload(a)))
            let bEnd := add(b, shl(5, mload(b)))
            c := mload(0x40) // Set `c` to the free memory pointer.
            a := add(a, s)
            b := add(b, s)
            let k := c
            for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {
                let u := mload(a)
                let v := mload(b)
                if iszero(xor(u, v)) {
                    a := add(a, s)
                    b := add(b, s)
                    continue
                }
                if iszero(lt(add(u, signed), add(v, signed))) {
                    b := add(b, s)
                    continue
                }
                k := add(k, s)
                mstore(k, u)
                a := add(a, s)
            }
            for {} iszero(gt(a, aEnd)) {} {
                k := add(k, s)
                mstore(k, mload(a))
                a := add(a, s)
            }
            mstore(c, shr(5, sub(k, c))) // Store the length of `c`.
            mstore(0x40, add(k, s)) // Allocate the memory for `c`.
        }
    }

    /// @dev Returns the sorted set intersection between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function _intersection(uint256[] memory a, uint256[] memory b, uint256 signed)
        private
        pure
        returns (uint256[] memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let s := 0x20
            let aEnd := add(a, shl(5, mload(a)))
            let bEnd := add(b, shl(5, mload(b)))
            c := mload(0x40) // Set `c` to the free memory pointer.
            a := add(a, s)
            b := add(b, s)
            let k := c
            for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {
                let u := mload(a)
                let v := mload(b)
                if iszero(xor(u, v)) {
                    k := add(k, s)
                    mstore(k, u)
                    a := add(a, s)
                    b := add(b, s)
                    continue
                }
                if iszero(lt(add(u, signed), add(v, signed))) {
                    b := add(b, s)
                    continue
                }
                a := add(a, s)
            }
            mstore(c, shr(5, sub(k, c))) // Store the length of `c`.
            mstore(0x40, add(k, s)) // Allocate the memory for `c`.
        }
    }

    /// @dev Returns the sorted set union of `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function _union(uint256[] memory a, uint256[] memory b, uint256 signed)
        private
        pure
        returns (uint256[] memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let s := 0x20
            let aEnd := add(a, shl(5, mload(a)))
            let bEnd := add(b, shl(5, mload(b)))
            c := mload(0x40) // Set `c` to the free memory pointer.
            a := add(a, s)
            b := add(b, s)
            let k := c
            for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {
                let u := mload(a)
                let v := mload(b)
                if iszero(xor(u, v)) {
                    k := add(k, s)
                    mstore(k, u)
                    a := add(a, s)
                    b := add(b, s)
                    continue
                }
                if iszero(lt(add(u, signed), add(v, signed))) {
                    k := add(k, s)
                    mstore(k, v)
                    b := add(b, s)
                    continue
                }
                k := add(k, s)
                mstore(k, u)
                a := add(a, s)
            }
            for {} iszero(gt(a, aEnd)) {} {
                k := add(k, s)
                mstore(k, mload(a))
                a := add(a, s)
            }
            for {} iszero(gt(b, bEnd)) {} {
                k := add(k, s)
                mstore(k, mload(b))
                b := add(b, s)
            }
            mstore(c, shr(5, sub(k, c))) // Store the length of `c`.
            mstore(0x40, add(k, s)) // Allocate the memory for `c`.
        }
    }
}

File 4 of 35 : Escrow.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import { AtlETH } from "./AtlETH.sol";
import { IExecutionEnvironment } from "../interfaces/IExecutionEnvironment.sol";
import { IAtlas } from "../interfaces/IAtlas.sol";
import { ISolverContract } from "../interfaces/ISolverContract.sol";
import { IAtlasVerification } from "../interfaces/IAtlasVerification.sol";
import { IDAppControl } from "../interfaces/IDAppControl.sol";

import { SafeCall } from "../libraries/SafeCall/SafeCall.sol";
import { EscrowBits } from "../libraries/EscrowBits.sol";
import { CallBits } from "../libraries/CallBits.sol";
import { SafetyBits } from "../libraries/SafetyBits.sol";
import { AccountingMath } from "../libraries/AccountingMath.sol";
import { DAppConfig } from "../types/ConfigTypes.sol";
import "../types/SolverOperation.sol";
import "../types/UserOperation.sol";
import "../types/EscrowTypes.sol";
import "../types/LockTypes.sol";

/// @title Escrow
/// @author FastLane Labs
/// @notice This Escrow component of Atlas handles execution of stages by calling corresponding functions on the
/// Execution Environment contract.
abstract contract Escrow is AtlETH {
    using EscrowBits for uint256;
    using CallBits for uint32;
    using SafetyBits for Context;
    using SafeCall for address;

    constructor(
        uint256 escrowDuration,
        uint256 atlasSurchargeRate,
        uint256 bundlerSurchargeRate,
        address verification,
        address simulator,
        address initialSurchargeRecipient,
        address l2GasCalculator
    )
        AtlETH(
            escrowDuration,
            atlasSurchargeRate,
            bundlerSurchargeRate,
            verification,
            simulator,
            initialSurchargeRecipient,
            l2GasCalculator
        )
    {
        if (escrowDuration == 0) revert InvalidEscrowDuration();
    }

    /// @notice Executes the preOps logic defined in the Execution Environment.
    /// @param ctx Metacall context data from the Context struct.
    /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings.
    /// @param userOp UserOperation struct of the current metacall tx.
    /// @return preOpsData The data returned by the preOps call, if successful.
    function _executePreOpsCall(
        Context memory ctx,
        DAppConfig memory dConfig,
        UserOperation calldata userOp
    )
        internal
        withLockPhase(ExecutionPhase.PreOps)
        returns (bytes memory)
    {
        (bool _success, bytes memory _data) = ctx.executionEnvironment.call(
            abi.encodePacked(
                abi.encodeCall(IExecutionEnvironment.preOpsWrapper, userOp), ctx.setAndPack(ExecutionPhase.PreOps)
            )
        );

        if (_success) {
            if (dConfig.callConfig.needsPreOpsReturnData()) {
                return abi.decode(_data, (bytes));
            } else {
                return new bytes(0);
            }
        }

        if (ctx.isSimulation) revert PreOpsSimFail();
        revert PreOpsFail();
    }

    /// @notice Executes the user operation logic defined in the Execution Environment.
    /// @param ctx Metacall context data from the Context struct.
    /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings.
    /// @param userOp UserOperation struct containing the user's transaction data.
    /// @param returnData Data returned from previous call phases.
    /// @return userData Data returned from executing the UserOperation, if the call was successful.
    function _executeUserOperation(
        Context memory ctx,
        DAppConfig memory dConfig,
        UserOperation calldata userOp,
        bytes memory returnData
    )
        internal
        withLockPhase(ExecutionPhase.UserOperation)
        returns (bytes memory)
    {
        bool _success;
        bytes memory _data;

        // Calculate gas limit ceiling, including gas to return gracefully even if userOp call is OOG.
        uint256 _gasLimit = gasleft() * 63 / 64 - _GRACEFUL_RETURN_GAS_OFFSET;
        // Use the smaller of userOp.gas and the gas limit ceiling
        _gasLimit = userOp.gas < _gasLimit ? userOp.gas : _gasLimit;

        if (!_borrow(userOp.value)) {
            revert InsufficientEscrow();
        }

        (_success, _data) = ctx.executionEnvironment.call{ value: userOp.value, gas: _gasLimit }(
            abi.encodePacked(
                abi.encodeCall(IExecutionEnvironment.userWrapper, userOp), ctx.setAndPack(ExecutionPhase.UserOperation)
            )
        );

        if (_success) {
            // Handle formatting of returnData
            if (dConfig.callConfig.needsUserReturnData()) {
                return abi.decode(_data, (bytes));
            } else {
                return returnData;
            }
        }

        // revert for failed
        if (ctx.isSimulation) revert UserOpSimFail();
        revert UserOpFail();
    }

    /// @notice Checks if the trusted operation hash matches and sets the appropriate error bit if it doesn't.
    /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings.
    /// @param prevalidated Boolean flag indicating whether the SolverOperation has been prevalidated to skip certain
    /// checks.
    /// @param userOp UserOperation struct containing the user's transaction data relevant to this SolverOperation.
    /// @param solverOp SolverOperation struct containing the solver's bid and execution data.
    /// @param result The current result bitmask that tracks the status of various checks and validations.
    /// @return The updated result bitmask with the AltOpHashMismatch bit set if the operation hash does not match.
    function _checkTrustedOpHash(
        DAppConfig memory dConfig,
        bool prevalidated,
        UserOperation calldata userOp,
        SolverOperation calldata solverOp,
        uint256 result
    )
        internal
        returns (uint256)
    {
        if (dConfig.callConfig.allowsTrustedOpHash() && !prevalidated && !_handleAltOpHash(userOp, solverOp)) {
            result |= 1 << uint256(SolverOutcome.AltOpHashMismatch);
        }
        return result;
    }

    /// @notice Attempts to execute a SolverOperation and determine if it wins the auction.
    /// @param ctx Context struct containing the current state of the escrow lock.
    /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings.
    /// @param userOp UserOperation struct containing the user's transaction data relevant to this SolverOperation.
    /// @param solverOp SolverOperation struct containing the solver's bid and execution data.
    /// @param bidAmount The amount of bid submitted by the solver for this operation.
    /// @param prevalidated Boolean flag indicating whether the SolverOperation has been prevalidated to skip certain
    /// @param returnData Data returned from UserOp execution, used as input if necessary.
    /// @return bidAmount The determined bid amount for the SolverOperation if all validations pass and the operation is
    /// executed successfully; otherwise, returns 0.
    function _executeSolverOperation(
        Context memory ctx,
        DAppConfig memory dConfig,
        UserOperation calldata userOp,
        SolverOperation calldata solverOp,
        uint256 bidAmount,
        bool prevalidated,
        bytes memory returnData
    )
        internal
        returns (uint256)
    {
        // Set the gas baseline
        uint256 _gasWaterMark = gasleft();
        uint256 _result;
        if (!prevalidated) {
            _result = VERIFICATION.verifySolverOp(
                solverOp, ctx.userOpHash, userOp.maxFeePerGas, ctx.bundler, dConfig.callConfig.allowsTrustedOpHash()
            );
            _result = _checkSolverBidToken(solverOp.bidToken, dConfig.bidToken, _result);
        }

        // Verify the transaction.
        if (_result.canExecute()) {
            uint256 _gasLimit;
            // Verify gasLimit again
            (_result, _gasLimit) = _validateSolverOpGasAndValue(dConfig, solverOp, _gasWaterMark, _result);
            _result |= _validateSolverOpDeadline(solverOp, dConfig);

            // Check for trusted operation hash
            _result = _checkTrustedOpHash(dConfig, prevalidated, userOp, solverOp, _result);

            // If there are no errors, attempt to execute
            if (_result.canExecute()) {
                SolverTracker memory _solverTracker;

                // Execute the solver call
                (_result, _solverTracker) = _solverOpWrapper(ctx, solverOp, bidAmount, _gasLimit, returnData);

                if (_result.executionSuccessful()) {
                    // First successful solver call that paid what it bid
                    emit SolverTxResult(
                        solverOp.solver, solverOp.from, dConfig.to, solverOp.bidToken, bidAmount, true, true, _result
                    );

                    ctx.solverSuccessful = true;
                    ctx.solverOutcome = uint24(_result);
                    return _solverTracker.bidAmount;
                }
            }
        }

        // If we reach this point, the solver call did not execute successfully.
        ctx.solverOutcome = uint24(_result);

        // Account for failed SolverOperation gas costs
        _handleSolverAccounting(solverOp, _gasWaterMark, _result, !prevalidated);

        emit SolverTxResult(
            solverOp.solver,
            solverOp.from,
            dConfig.to,
            solverOp.bidToken,
            bidAmount,
            _result.executedWithError(),
            false,
            _result
        );

        return 0;
    }

    /// @notice Allocates the winning bid amount after a successful SolverOperation execution.
    /// @dev This function handles the allocation of the bid amount to the appropriate recipients as defined in the
    /// DApp's configuration. It calls the allocateValue function in the Execution Environment, which is responsible for
    /// distributing the bid amount. Note that balance discrepancies leading to payment failures are typically due to
    /// issues in the DAppControl contract, not the execution environment itself.
    /// @param ctx Context struct containing the current state of the escrow lock.
    /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings.
    /// @param bidAmount The winning solver's bid amount, to be allocated.
    /// @param returnData Data returned from the execution of the UserOperation, which may influence how the bid amount
    /// is allocated.
    function _allocateValue(
        Context memory ctx,
        DAppConfig memory dConfig,
        uint256 bidAmount,
        bytes memory returnData
    )
        internal
        withLockPhase(ExecutionPhase.AllocateValue)
    {
        (bool _success, bytes memory _returnData) = ctx.executionEnvironment.call(
            abi.encodePacked(
                abi.encodeCall(IExecutionEnvironment.allocateValue, (dConfig.bidToken, bidAmount, returnData)),
                ctx.setAndPack(ExecutionPhase.AllocateValue)
            )
        );

        // If the call from Atlas to EE succeeded, decode the return data to check if the allocateValue delegatecall
        // from EE to DAppControl succeeded.
        if (_success) _success = abi.decode(_returnData, (bool));

        // Revert if allocateValue failed at any point, unless the call config allows allocate value failure.
        if (!_success && !dConfig.callConfig.allowAllocateValueFailure()) {
            if (ctx.isSimulation) revert AllocateValueSimFail();
            revert AllocateValueFail();
        }

        // paymentsSuccessful is part of the data forwarded to the postOps hook, dApps can easily check the value by
        // calling _paymentsSuccessful()
        ctx.paymentsSuccessful = _success;
    }

    /// @notice Executes post-operation logic after SolverOperation, depending on the outcome of the auction.
    /// @dev Calls the postOpsWrapper function in the Execution Environment, which handles any necessary cleanup or
    /// finalization logic after the winning SolverOperation.
    /// @param ctx Context struct containing the current state of the escrow lock.
    /// @param solved Boolean indicating whether a SolverOperation was successful and won the auction.
    /// @param returnData Data returned from execution of the UserOp call, which may be required for the postOps logic.
    function _executePostOpsCall(
        Context memory ctx,
        bool solved,
        bytes memory returnData
    )
        internal
        withLockPhase(ExecutionPhase.PostOps)
    {
        (bool _success,) = ctx.executionEnvironment.call(
            abi.encodePacked(
                abi.encodeCall(IExecutionEnvironment.postOpsWrapper, (solved, returnData)),
                ctx.setAndPack(ExecutionPhase.PostOps)
            )
        );

        if (!_success) {
            if (ctx.isSimulation) revert PostOpsSimFail();
            revert PostOpsFail();
        }
    }

    /// @notice Validates a SolverOperation's gas requirements against the escrow state.
    /// @dev Performs a series of checks to ensure that a SolverOperation can be executed within the defined parameters
    /// and limits. This includes verifying that the operation is within the gas limit and that the solver has
    /// sufficient balance in escrow to cover the gas costs.
    /// @param dConfig DApp configuration data, including solver gas limits and operation parameters.
    /// @param solverOp The SolverOperation being validated.
    /// @param gasWaterMark The initial gas measurement before validation begins, used to ensure enough gas remains for
    /// validation logic.
    /// @param result The current result bitmap, which will be updated with the outcome of the gas validation checks.
    /// @return result Updated result flags after performing the validation checks, including any new errors
    /// encountered.
    /// @return gasLimit The calculated gas limit for the SolverOperation, considering the operation's gas usage and
    /// the protocol's gas buffers.
    function _validateSolverOpGasAndValue(
        DAppConfig memory dConfig,
        SolverOperation calldata solverOp,
        uint256 gasWaterMark,
        uint256 result
    )
        internal
        view
        returns (uint256, uint256 gasLimit)
    {
        if (gasWaterMark < _VALIDATION_GAS_LIMIT + dConfig.solverGasLimit) {
            // Make sure to leave enough gas for dApp validation calls
            result |= 1 << uint256(SolverOutcome.UserOutOfGas);
            return (result, gasLimit); // gasLimit = 0
        }

        gasLimit = AccountingMath.solverGasLimitScaledDown(solverOp.gas, dConfig.solverGasLimit) + _FASTLANE_GAS_BUFFER;

        uint256 _gasCost = (tx.gasprice * gasLimit) + _getCalldataCost(solverOp.data.length);

        // Verify that we can lend the solver their tx value
        if (solverOp.value > address(this).balance) {
            result |= 1 << uint256(SolverOutcome.CallValueTooHigh);
            return (result, gasLimit);
        }

        // subtract out the gas buffer since the solver's metaTx won't use it
        gasLimit -= _FASTLANE_GAS_BUFFER;

        uint256 _solverBalance = S_accessData[solverOp.from].bonded;

        // see if solver's escrow can afford tx gascost
        if (_gasCost > _solverBalance) {
            // charge solver for calldata so that we can avoid vampire attacks from solver onto user
            result |= 1 << uint256(SolverOutcome.InsufficientEscrow);
        }

        return (result, gasLimit);
    }

    /// @notice Validates a SolverOperation's deadline against the current block.
    /// @param solverOp The SolverOperation being validated.
    /// @param dConfig DApp configuration data, including solver gas limits and operation parameters.
    /// @return result Updated result flags after performing the validation checks, including any new errors
    function _validateSolverOpDeadline(
        SolverOperation calldata solverOp,
        DAppConfig memory dConfig
    )
        internal
        view
        returns (uint256 result)
    {
        if (solverOp.deadline != 0 && block.number > solverOp.deadline) {
            result |= (
                1
                    << uint256(
                        dConfig.callConfig.allowsTrustedOpHash()
                            ? uint256(SolverOutcome.DeadlinePassedAlt)
                            : uint256(SolverOutcome.DeadlinePassed)
                    )
            );
            return result;
        }

        uint256 lastAccessedBlock = S_accessData[solverOp.from].lastAccessedBlock;

        if (lastAccessedBlock >= block.number) {
            result |= 1 << uint256(SolverOutcome.PerBlockLimit);
        }
    }

    /// @notice Determines the bid amount for a SolverOperation based on verification and validation results.
    /// @dev This function assesses whether a SolverOperation meets the criteria for execution by verifying it against
    /// the Atlas protocol's rules and the current Context lock state. It checks for valid execution based on the
    /// SolverOperation's specifics, like gas usage and deadlines. The function aims to protect against malicious
    /// bundlers by ensuring solvers are not unfairly charged for on-chain bid finding gas usage. If the operation
    /// passes verification and validation, and if it's eligible for bid amount determination, the function
    /// attempts to execute and determine the bid amount.
    /// @param ctx The Context struct containing the current state of the escrow lock.
    /// @param dConfig The DApp configuration data, including parameters relevant to solver bid validation.
    /// @param userOp The UserOperation associated with this SolverOperation, providing context for the bid amount
    /// determination.
    /// @param solverOp The SolverOperation being assessed, containing the solver's bid amount.
    /// @param returnData Data returned from the execution of the UserOp call.
    /// @return bidAmount The determined bid amount for the SolverOperation if all validations pass and the operation is
    /// executed successfully; otherwise, returns 0.
    function _getBidAmount(
        Context memory ctx,
        DAppConfig memory dConfig,
        UserOperation calldata userOp,
        SolverOperation calldata solverOp,
        bytes memory returnData
    )
        internal
        returns (uint256 bidAmount)
    {
        // NOTE: To prevent a malicious bundler from aggressively collecting storage refunds,
        // solvers should not be on the hook for any 'on chain bid finding' gas usage.

        uint256 _gasWaterMark = gasleft();
        uint256 _gasLimit;

        uint256 _result = VERIFICATION.verifySolverOp(
            solverOp, ctx.userOpHash, userOp.maxFeePerGas, ctx.bundler, dConfig.callConfig.allowsTrustedOpHash()
        );

        _result = _checkSolverBidToken(solverOp.bidToken, dConfig.bidToken, _result);
        (_result, _gasLimit) = _validateSolverOpGasAndValue(dConfig, solverOp, _gasWaterMark, _result);
        _result |= _validateSolverOpDeadline(solverOp, dConfig);

        // Verify the transaction.
        if (!_result.canExecute()) return 0;

        if (dConfig.callConfig.allowsTrustedOpHash()) {
            if (!_handleAltOpHash(userOp, solverOp)) {
                return (0);
            }
        }

        (bool _success, bytes memory _data) = address(this).call{ gas: _gasLimit }(
            abi.encodeCall(this.solverCall, (ctx, solverOp, solverOp.bidAmount, returnData))
        );

        // The `solverCall()` above should always revert as key.bidFind is always true when it's called in the context
        // of this function. Therefore `success` should always be false below, and the revert should be unreachable.
        if (_success) {
            revert Unreachable();
        }

        if (bytes4(_data) == BidFindSuccessful.selector) {
            // Get the uint256 from the memory array
            assembly {
                let dataLocation := add(_data, 0x20)
                bidAmount := mload(add(dataLocation, sub(mload(_data), 32)))
            }
            return bidAmount;
        }

        return 0;
    }

    /// @notice Validates UserOp hashes provided by the SolverOperation, using the alternative set of hashed parameters.
    /// @param userOp The UserOperation struct, providing the baseline parameters for comparison.
    /// @param solverOp The SolverOperation struct being validated against the UserOperation.
    /// @return A boolean value indicating whether the SolverOperation passed the alternative hash check, with `true`
    /// meaning it is considered valid
    function _handleAltOpHash(
        UserOperation calldata userOp,
        SolverOperation calldata solverOp
    )
        internal
        returns (bool)
    {
        // These failures should be attributed to bundler maliciousness
        if (userOp.control != solverOp.control) {
            return false;
        }
        if (!(userOp.deadline == 0 || solverOp.deadline == 0 || solverOp.deadline == userOp.deadline)) {
            return false;
        }
        bytes32 _hashId = keccak256(abi.encodePacked(solverOp.userOpHash, solverOp.from, solverOp.deadline));
        if (S_solverOpHashes[_hashId]) {
            return false;
        }
        S_solverOpHashes[_hashId] = true;
        return true;
    }

    /// @notice Checks if the solver's bid token matches the dApp's bid token.
    /// @param solverBidToken The solver's bid token address.
    /// @param dConfigBidToken The dApp's bid token address.
    /// @param result The current result bitmap, which will be updated with the outcome of the bid token check.
    /// @return The updated result bitmap, with the SolverOutcome.InvalidBidToken flag set if the bid token check fails.
    function _checkSolverBidToken(
        address solverBidToken,
        address dConfigBidToken,
        uint256 result
    )
        internal
        pure
        returns (uint256)
    {
        if (solverBidToken != dConfigBidToken) {
            return result | 1 << uint256(SolverOutcome.InvalidBidToken);
        }
        return result;
    }

    /// @notice Wraps the execution of a SolverOperation and handles potential errors.
    /// @param ctx The current lock data.
    /// @param solverOp The SolverOperation struct containing the operation's execution data.
    /// @param bidAmount The bid amount associated with the SolverOperation.
    /// @param gasLimit The gas limit for executing the SolverOperation, calculated based on the operation's
    /// requirements and protocol buffers.
    /// @param returnData Data returned from the execution of the associated UserOperation, which may be required
    /// for the SolverOperation's logic.
    /// @return result SolverOutcome enum value encoded as a uint256 bitmap, representing the result of the
    /// SolverOperation
    /// @return solverTracker Tracking data for the solver's bid
    function _solverOpWrapper(
        Context memory ctx,
        SolverOperation calldata solverOp,
        uint256 bidAmount,
        uint256 gasLimit,
        bytes memory returnData
    )
        internal
        returns (uint256 result, SolverTracker memory solverTracker)
    {
        // Calls the solverCall function, just below this function, which will handle calling solverPreTryCatch and
        // solverPostTryCatch via the ExecutionEnvironment, and in between those two hooks, the actual solver call
        // directly from Atlas to the solver contract (not via the ExecutionEnvironment).
        (bool _success, bytes memory _data) =
            address(this).call{ gas: gasLimit }(abi.encodeCall(this.solverCall, (ctx, solverOp, bidAmount, returnData)));

        if (_success) {
            // If solverCall() was successful, intentionally leave uint256 result unset as 0 indicates success.
            solverTracker = abi.decode(_data, (SolverTracker));
        } else {
            // If solverCall() failed, catch the error and encode the failure case in the result uint accordingly.
            bytes4 _errorSwitch = bytes4(_data);
            if (_errorSwitch == AlteredControl.selector) {
                result = 1 << uint256(SolverOutcome.AlteredControl);
            } else if (_errorSwitch == InsufficientEscrow.selector) {
                result = 1 << uint256(SolverOutcome.InsufficientEscrow);
            } else if (_errorSwitch == PreSolverFailed.selector) {
                result = 1 << uint256(SolverOutcome.PreSolverFailed);
            } else if (_errorSwitch == SolverOpReverted.selector) {
                result = 1 << uint256(SolverOutcome.SolverOpReverted);
            } else if (_errorSwitch == PostSolverFailed.selector) {
                result = 1 << uint256(SolverOutcome.PostSolverFailed);
            } else if (_errorSwitch == BidNotPaid.selector) {
                result = 1 << uint256(SolverOutcome.BidNotPaid);
            } else if (_errorSwitch == InvalidSolver.selector) {
                result = 1 << uint256(SolverOutcome.InvalidSolver);
            } else if (_errorSwitch == BalanceNotReconciled.selector) {
                result = 1 << uint256(SolverOutcome.BalanceNotReconciled);
            } else if (_errorSwitch == CallbackNotCalled.selector) {
                result = 1 << uint256(SolverOutcome.CallbackNotCalled);
            } else if (_errorSwitch == InvalidEntry.selector) {
                // DAppControl is attacking solver contract - treat as AlteredControl
                result = 1 << uint256(SolverOutcome.AlteredControl);
            } else {
                result = 1 << uint256(SolverOutcome.EVMError);
            }
        }
    }

    /// @notice Executes the SolverOperation logic, including preSolver and postSolver hooks via the Execution
    /// Environment, as well as the actual solver call directly from Atlas to the solver contract.
    /// @param ctx The Context struct containing lock data and the Execution Environment address.
    /// @param solverOp The SolverOperation to be executed.
    /// @param bidAmount The bid amount associated with the SolverOperation.
    /// @param returnData Data returned from previous call phases.
    /// @return solverTracker Additional data for handling the solver's bid in different scenarios.
    function solverCall(
        Context memory ctx,
        SolverOperation calldata solverOp,
        uint256 bidAmount,
        bytes calldata returnData
    )
        external
        payable
        returns (SolverTracker memory solverTracker)
    {
        if (msg.sender != address(this)) revert InvalidEntry();

        bytes memory _data;
        bool _success;

        // Set the solver lock and solver address at the beginning to ensure reliability
        t_solverLock = uint256(uint160(solverOp.from));
        t_solverTo = solverOp.solver;

        // ------------------------------------- //
        //             Pre-Solver Call           //
        // ------------------------------------- //

        _setLockPhase(uint8(ExecutionPhase.PreSolver));

        (_success, _data) = ctx.executionEnvironment.call(
            abi.encodePacked(
                abi.encodeCall(IExecutionEnvironment.solverPreTryCatch, (bidAmount, solverOp, returnData)),
                ctx.setAndPack(ExecutionPhase.PreSolver)
            )
        );

        // If ExecutionEnvironment.solverPreTryCatch() failed, bubble up the error
        if (!_success) {
            assembly {
                revert(add(_data, 32), mload(_data))
            }
        }

        // Update solverTracker with returned data
        solverTracker = abi.decode(_data, (SolverTracker));

        // ------------------------------------- //
        //              Solver Call              //
        // ------------------------------------- //

        _setLockPhase(uint8(ExecutionPhase.SolverOperation));

        // Make sure there's enough value in Atlas for the Solver
        if (!_borrow(solverOp.value)) revert InsufficientEscrow();

        // Optimism's SafeCall lib allows us to limit how much returndata gets copied to memory, to prevent OOG attacks.
        _success = solverOp.solver.safeCall(
            gasleft(),
            solverOp.value,
            abi.encodeCall(
                ISolverContract.atlasSolverCall,
                (
                    solverOp.from,
                    ctx.executionEnvironment,
                    solverOp.bidToken,
                    bidAmount,
                    solverOp.data,
                    // Only pass the returnData (either from userOp or preOps) if the dApp requires it
                    _activeCallConfig().forwardReturnData() ? returnData : new bytes(0)
                )
            )
        );

        if (!_success) revert SolverOpReverted();

        // ------------------------------------- //
        //            Post-Solver Call           //
        // ------------------------------------- //

        _setLockPhase(uint8(ExecutionPhase.PostSolver));

        (_success, _data) = ctx.executionEnvironment.call(
            abi.encodePacked(
                abi.encodeCall(IExecutionEnvironment.solverPostTryCatch, (solverOp, returnData, solverTracker)),
                ctx.setAndPack(ExecutionPhase.PostSolver)
            )
        );

        // If ExecutionEnvironment.solverPostTryCatch() failed, bubble up the error
        if (!_success) {
            assembly {
                revert(add(_data, 32), mload(_data))
            }
        }

        // Update solverTracker with returned data
        solverTracker = abi.decode(_data, (SolverTracker));

        // ------------------------------------- //
        //              Final Checks             //
        // ------------------------------------- //

        // Verify that the solver repaid their borrowed solverOp.value by calling `reconcile()`. If `reconcile()` did
        // not fully repay the borrowed amount, the `postSolverCall` might have covered the outstanding debt via
        // `contribute()`. This final check ensures that the solver has fulfilled their repayment obligations before
        // proceeding.
        (, bool _calledback, bool _fulfilled) = _solverLockData();
        if (!_calledback) revert CallbackNotCalled();
        if (!_fulfilled && !_isBalanceReconciled()) revert BalanceNotReconciled();

        // Check if this is an on-chain, ex post bid search by verifying the `ctx.bidFind` flag.
        // If the flag is set, revert with `BidFindSuccessful` and include the solver's bid amount in `solverTracker`.
        // This indicates that the bid search process has completed successfully.
        if (ctx.bidFind) revert BidFindSuccessful(solverTracker.bidAmount);
    }

    receive() external payable { }
}

File 5 of 35 : Factory.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

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

import { IDAppControl } from "../interfaces/IDAppControl.sol";
import { DAppConfig } from "../types/ConfigTypes.sol";
import { UserOperation } from "../types/UserOperation.sol";
import { AtlasErrors } from "../types/AtlasErrors.sol";

abstract contract Factory {
    address public immutable FACTORY_LIB;
    bytes32 internal immutable _FACTORY_BASE_SALT;

    constructor(address factoryLib) {
        FACTORY_LIB = factoryLib;
        _FACTORY_BASE_SALT = keccak256(abi.encodePacked(block.chainid, address(this)));
    }

    /// @notice Creates a new Execution Environment for the caller, given a DAppControl contract address.
    /// @param user The address of the user for whom the execution environment is being created.
    /// @param control The address of the DAppControl contract for which the execution environment is being created.
    /// @return executionEnvironment The address of the newly created Execution Environment instance.
    function createExecutionEnvironment(
        address user,
        address control
    )
        external
        returns (address executionEnvironment)
    {
        if (msg.sender != user && msg.sender != control) revert AtlasErrors.Unauthorized();
        uint32 _callConfig = IDAppControl(control).CALL_CONFIG();
        executionEnvironment =
            _getOrCreateExecutionEnvironment({ user: user, control: control, callConfig: _callConfig });
    }

    /// @notice Retrieves the address and configuration of an existing execution environment for a given user and DApp
    /// control contract.
    /// @param user The address of the user for whom the execution environment is being queried.
    /// @param control The address of the DAppControl contract associated with the execution environment.
    /// @return executionEnvironment The address of the queried execution environment.
    /// @return callConfig The call configuration used by the execution environment, retrieved from the DAppControl
    /// contract.
    /// @return exists A boolean indicating whether the execution environment already exists (true) or not (false).
    function getExecutionEnvironment(
        address user,
        address control
    )
        external
        returns (address executionEnvironment, uint32 callConfig, bool exists)
    {
        callConfig = IDAppControl(control).CALL_CONFIG();
        executionEnvironment = _getExecutionEnvironmentCustom(user, control, callConfig);
        exists = executionEnvironment.code.length != 0;
    }

    /// @notice Gets an existing execution environment or creates a new one if it does not exist for the specified user
    /// operation.
    /// @param userOp The user operation containing details about the user and the DAppControl contract.
    /// @return executionEnvironment The address of the execution environment that was found or created.
    /// @return dConfig The DAppConfig for the execution environment, specifying how operations should be handled.
    function _getOrCreateExecutionEnvironment(UserOperation calldata userOp)
        internal
        returns (address executionEnvironment, DAppConfig memory dConfig)
    {
        dConfig = IDAppControl(userOp.control).getDAppConfig(userOp);
        executionEnvironment = _getOrCreateExecutionEnvironment({
            user: userOp.from,
            control: userOp.control,
            callConfig: dConfig.callConfig
        });
    }

    /// @notice Deploys a new execution environment or retrieves the address of an existing one based on the DApp
    /// control, user, and configuration.
    /// @dev Uses the `create2` opcode for deterministic deployment, allowing the calculation of the execution
    /// environment's address before deployment. The deployment uses a combination of the DAppControl address, user
    /// address, call configuration, and a unique salt to ensure the uniqueness and predictability of the environment's
    /// address.
    /// @param user The address of the user for whom the execution environment is being set.
    /// @param control The address of the DAppControl contract providing the operational context.
    /// @param callConfig CallConfig settings of the DAppControl contract.
    /// @return executionEnvironment The address of the newly created or already existing execution environment.
    function _getOrCreateExecutionEnvironment(
        address user,
        address control,
        uint32 callConfig
    )
        internal
        returns (address executionEnvironment)
    {
        bytes32 _salt = _computeSalt(user, control, callConfig);

        bytes memory returnData = _delegatecallFactoryLib(
            abi.encodeCall(FactoryLib.getOrCreateExecutionEnvironment, (user, control, callConfig, _salt))
        );

        return abi.decode(returnData, (address));
    }

    /// @notice Generates the address of a user's execution environment affected by deprecated callConfig changes in the
    /// DAppControl.
    /// @dev Calculates the deterministic address of the execution environment based on the user, control,
    /// callConfig, and controlCodeHash, ensuring consistency across changes in callConfig.
    /// @param user The address of the user for whom the execution environment's address is being generated.
    /// @param control The address of the DAppControl contract associated with the execution environment.
    /// @param callConfig The configuration flags defining the behavior of the execution environment.
    /// @return executionEnvironment The address of the user's execution environment.
    function _getExecutionEnvironmentCustom(
        address user,
        address control,
        uint32 callConfig
    )
        internal
        returns (address executionEnvironment)
    {
        bytes32 _salt = _computeSalt(user, control, callConfig);

        bytes memory returnData = _delegatecallFactoryLib(
            abi.encodeCall(FactoryLib.getExecutionEnvironmentCustom, (user, control, callConfig, _salt))
        );

        return abi.decode(returnData, (address));
    }

    function _computeSalt(address user, address control, uint32 callConfig) internal view returns (bytes32) {
        return keccak256(abi.encodePacked(_FACTORY_BASE_SALT, user, control, callConfig));
    }

    function _delegatecallFactoryLib(bytes memory data) internal returns (bytes memory) {
        (bool _success, bytes memory _result) = FACTORY_LIB.delegatecall(data);
        if (!_success) {
            assembly {
                revert(add(_result, 32), mload(_result))
            }
        }
        return _result;
    }
}

File 6 of 35 : SolverOperation.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

bytes32 constant SOLVER_TYPEHASH = keccak256(
    "SolverOperation(address from,address to,uint256 value,uint256 gas,uint256 maxFeePerGas,uint256 deadline,address solver,address control,bytes32 userOpHash,address bidToken,uint256 bidAmount,bytes data)"
);

// NOTE: The calldata length of this SolverOperation struct is 608 bytes when the `data` field is excluded. This value
// is stored in the `_SOLVER_OP_BASE_CALLDATA` constant in AtlasConstants.sol and must be kept up-to-date with any
// changes to this struct.
struct SolverOperation {
    address from; // Solver address
    address to; // Atlas address
    uint256 value; // Amount of ETH required for the solver operation (used in `value` field of the solver call)
    uint256 gas; // Gas limit for the solver operation
    uint256 maxFeePerGas; // maxFeePerGas solver is willing to pay.  This goes to validator, not dApp or user
    uint256 deadline; // block.number deadline for the solver operation
    address solver; // Nested "to" address (used in `to` field of the solver call)
    address control; // DAppControl address
    bytes32 userOpHash; // hash of User's Operation, for verification of user's tx (if not matched, solver wont be
        // charged for gas)
    address bidToken; // address(0) for ETH
    uint256 bidAmount; // Amount of bidToken that the solver bids
    bytes data; // Solver op calldata (used in `data` field of the solver call)
    bytes signature; // Solver operation signature signed by SolverOperation.from
}

File 7 of 35 : UserOperation.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

// Default UserOperation typehash
bytes32 constant USER_TYPEHASH_DEFAULT = keccak256(
    "UserOperation(address from,address to,uint256 value,uint256 gas,uint256 maxFeePerGas,uint256 nonce,uint256 deadline,address dapp,address control,uint32 callConfig,address sessionKey,bytes data)"
);

// Trusted UserOperation typehash
// NOTE: This is explicitly for the 'trustedOpHash' configuration option meant so that solvers can submit
// SolverOperations
// prior to seeing the UserOperation or its hash. In this scenario, the Solvers should trust the signer of the
// UserOperation.
bytes32 constant USER_TYPEHASH_TRUSTED = keccak256(
    "UserOperation(address from,address to,address dapp,address control,uint32 callConfig,address sessionKey)"
);

struct UserOperation {
    address from; // User address
    address to; // Atlas address
    uint256 value; // Amount of ETH required for the user operation (used in `value` field of the user call)
    uint256 gas; // Gas limit for the user operation
    uint256 maxFeePerGas; // Max fee per gas for the user operation
    uint256 nonce; // Atlas nonce of the user operation available in the AtlasVerification contract
    uint256 deadline; // block.number deadline for the user operation
    address dapp; // Nested "to" for user's call (used in `to` field of the user call)
    address control; // Address of the DAppControl contract
    uint32 callConfig; // Call configuration expected by user, refer to
        // `src/contracts/types/ConfigTypes.sol:CallConfig`
    address sessionKey; // Address of the temporary session key which is used to sign the DappOperation
    bytes data; // User operation calldata (used in `data` field of the user call)
    bytes signature; // User operation signature signed by UserOperation.from
}

File 8 of 35 : LockTypes.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

struct Context {
    bytes32 userOpHash; // not packed
    address executionEnvironment; // not packed
    uint24 solverOutcome;
    uint8 solverIndex;
    uint8 solverCount;
    uint8 callDepth;
    uint8 phase;
    bool solverSuccessful;
    bool paymentsSuccessful;
    bool bidFind;
    bool isSimulation;
    address bundler;
}

enum ExecutionPhase {
    Uninitialized,
    PreOps,
    UserOperation,
    PreSolver,
    SolverOperation,
    PostSolver,
    AllocateValue,
    PostOps,
    FullyLocked
}

File 9 of 35 : ConfigTypes.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

struct DAppConfig {
    address to; // Address of the DAppControl contract
    uint32 callConfig; // Configuration
    address bidToken; // address(0) for ETH
    uint32 solverGasLimit; // Max gas limit for solverOps
}

struct CallConfig {
    // userNoncesSequential: The userOp nonce must be the next sequential nonce for that user’s address in Atlas’
    // nonce system. If false, the userOp nonces are allowed to be non-sequential (unordered), as long as they are
    // unique.
    bool userNoncesSequential;
    // dappNoncesSequential: The dappOp nonce must be the next sequential nonce for that dApp signer’s address in
    // Atlas’ nonce system. If false, the dappOp nonce is not checked, as the dAppOp is tied to its userOp's nonce via
    // the callChainHash.
    bool dappNoncesSequential;
    // requirePreOps: The preOps hook is executed before the userOp is executed. If false, the preOps hook is skipped.
    // the dapp control should check the validity of the user operation (whether its dapps can support userOp.dapp and
    // userOp.data) in the preOps hook.
    bool requirePreOps;
    // trackPreOpsReturnData: The return data from the preOps hook is passed to the next call phase. If false preOps
    // return data is discarded. If both trackPreOpsReturnData and trackUserReturnData are true, they are concatenated.
    bool trackPreOpsReturnData;
    // trackUserReturnData: The return data from the userOp call is passed to the next call phase. If false userOp
    // return data is discarded. If both trackPreOpsReturnData and trackUserReturnData are true, they are concatenated.
    bool trackUserReturnData;
    // delegateUser: The userOp call is made using delegatecall from the Execution Environment. If false, userOp is
    // called using call.
    bool delegateUser;
    // requirePreSolver: The preSolver hook is executed before the solverOp is executed. If false, the preSolver hook is
    // skipped.
    bool requirePreSolver;
    // requirePostSolver: The postSolver hook is executed after the solverOp is executed. If false, the postSolver hook
    // is skipped.
    bool requirePostSolver;
    // requirePostOps: The postOps hook is executed as the last step of the metacall. If false, the postOps hook is
    // skipped.
    bool requirePostOps;
    // zeroSolvers: Allow the metacall to proceed even if there are no solverOps. The solverOps do not necessarily need
    // to be successful, but at least 1 must exist.
    bool zeroSolvers;
    // reuseUserOp: If true, the metacall will revert if unsuccessful so as not to store nonce data, so the userOp can
    // be reused.
    bool reuseUserOp;
    // userAuctioneer: The user is allowed to be the auctioneer (the signer of the dAppOp). More than one auctioneer
    // option can be set to true for the same DAppControl.
    bool userAuctioneer;
    // solverAuctioneer: The solver is allowed to be the auctioneer (the signer of the dAppOp). If the solver is the
    // auctioneer then their solverOp must be the only one. More than one auctioneer option can be set to true for the
    // same DAppControl.
    bool solverAuctioneer;
    // unknownAuctioneer: Anyone is allowed to be the auctioneer - dAppOp.from must be the signer of the dAppOp, but the
    // usual signatory[] checks are skipped. More than one auctioneer option can be set to true for the same
    // DAppControl.
    bool unknownAuctioneer;
    // verifyCallChainHash: Check that the dAppOp callChainHash matches the actual callChainHash as calculated in
    // AtlasVerification.
    bool verifyCallChainHash;
    // forwardReturnData: The return data from previous steps is included as calldata in the call from the Execution
    // Environment to the solver contract. If false, return data is not passed to the solver contract.
    bool forwardReturnData;
    // requireFulfillment: If true, a winning solver must be found, otherwise the metacall will fail.
    bool requireFulfillment;
    // trustedOpHash: If true, the userOpHash excludes some userOp inputs such as `value`, `gas`, `maxFeePerGas`,
    // `nonce`, `deadline`, and `data`, implying solvers trust changes made to these parts of the userOp after signing
    // their associated solverOps.
    bool trustedOpHash;
    // invertBidValue: If true, the solver with the lowest successful bid wins.
    bool invertBidValue;
    // exPostBids: Bids are found on-chain using `_getBidAmount` in Atlas, and solverOp.bidAmount is used as the max
    // bid. If solverOp.bidAmount is 0, then there is no max bid limit for that solver.
    bool exPostBids;
    // allowAllocateValueFailure: If true, the metacall will proceed even if the value allocation fails. If false, the
    // metacall will revert if the value allocation fails.
    bool allowAllocateValueFailure;
}

enum CallConfigIndex {
    UserNoncesSequential,
    DAppNoncesSequential,
    RequirePreOps,
    TrackPreOpsReturnData,
    TrackUserReturnData,
    DelegateUser,
    RequirePreSolver,
    RequirePostSolver,
    RequirePostOpsCall,
    ZeroSolvers,
    ReuseUserOp,
    UserAuctioneer,
    SolverAuctioneer,
    UnknownAuctioneer,
    // Default = DAppAuctioneer
    VerifyCallChainHash,
    ForwardReturnData,
    RequireFulfillment,
    TrustedOpHash,
    InvertBidValue,
    ExPostBids,
    AllowAllocateValueFailure
}

File 10 of 35 : DAppOperation.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

bytes32 constant DAPP_TYPEHASH = keccak256(
    "DAppOperation(address from,address to,uint256 nonce,uint256 deadline,address control,address bundler,bytes32 userOpHash,bytes32 callChainHash)"
);

struct DAppOperation {
    address from; // signer of the DAppOperation
    address to; // Atlas address
    uint256 nonce; // Atlas nonce of the DAppOperation available in the AtlasVerification contract
    uint256 deadline; // block.number deadline for the DAppOperation
    address control; // DAppControl address
    address bundler; // Signer of the atlas tx (msg.sender)
    bytes32 userOpHash; // keccak256 of userOp.to, userOp.data
    bytes32 callChainHash; // keccak256 of the solvers' txs
    bytes signature; // DAppOperation signed by DAppOperation.from
}

File 11 of 35 : ValidCalls.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

/// @title ValidCallsResult
/// @notice Enum for ValidCallsResult
/// @dev A single ValidCallsResult is returned by `validateCalls` in AtlasVerification
enum ValidCallsResult {
    Valid,
    // Results below this line will cause metacall to revert
    UserFromInvalid,
    UserSignatureInvalid,
    DAppSignatureInvalid,
    UserNonceInvalid,
    InvalidDAppNonce,
    UnknownAuctioneerNotAllowed,
    InvalidAuctioneer,
    InvalidBundler,
    // Results above this line will cause metacall to revert
    InvertBidValueCannotBeExPostBids, // Threshold value (included in the revert range), any new reverting values should
        // be included above this line
    // Results below this line will cause metacall to gracefully return
    GasPriceHigherThanMax,
    TxValueLowerThanCallValue,
    TooManySolverOps,
    UserDeadlineReached,
    DAppDeadlineReached,
    ExecutionEnvEmpty,
    NoSolverOp,
    InvalidSequence,
    OpHashMismatch,
    DeadlineMismatch,
    InvalidControl,
    InvalidSolverGasLimit,
    InvalidCallConfig,
    CallConfigMismatch,
    DAppToInvalid,
    UserToInvalid,
    ControlMismatch,
    InvalidCallChainHash,
    DAppNotEnabled,
    BothUserAndDAppNoncesCannotBeSequential
}

File 12 of 35 : CallBits.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import { IDAppControl } from "../interfaces/IDAppControl.sol";

import "../types/ConfigTypes.sol";

library CallBits {
    uint32 internal constant _ONE = uint32(1);

    function buildCallConfig(address control) internal view returns (uint32 callConfig) {
        callConfig = IDAppControl(control).CALL_CONFIG();
    }

    function encodeCallConfig(CallConfig memory callConfig) internal pure returns (uint32 encodedCallConfig) {
        if (callConfig.userNoncesSequential) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.UserNoncesSequential);
        }
        if (callConfig.dappNoncesSequential) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.DAppNoncesSequential);
        }
        if (callConfig.requirePreOps) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.RequirePreOps);
        }
        if (callConfig.trackPreOpsReturnData) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.TrackPreOpsReturnData);
        }
        if (callConfig.trackUserReturnData) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.TrackUserReturnData);
        }
        if (callConfig.delegateUser) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.DelegateUser);
        }
        if (callConfig.requirePreSolver) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.RequirePreSolver);
        }
        if (callConfig.requirePostSolver) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.RequirePostSolver);
        }
        if (callConfig.requirePostOps) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.RequirePostOpsCall);
        }
        if (callConfig.zeroSolvers) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.ZeroSolvers);
        }
        if (callConfig.reuseUserOp) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.ReuseUserOp);
        }
        if (callConfig.userAuctioneer) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.UserAuctioneer);
        }
        if (callConfig.solverAuctioneer) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.SolverAuctioneer);
        }
        if (callConfig.unknownAuctioneer) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.UnknownAuctioneer);
        }
        if (callConfig.verifyCallChainHash) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.VerifyCallChainHash);
        }
        if (callConfig.forwardReturnData) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.ForwardReturnData);
        }
        if (callConfig.requireFulfillment) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.RequireFulfillment);
        }
        if (callConfig.trustedOpHash) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.TrustedOpHash);
        }
        if (callConfig.invertBidValue) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.InvertBidValue);
        }
        if (callConfig.exPostBids) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.ExPostBids);
        }
        if (callConfig.allowAllocateValueFailure) {
            encodedCallConfig ^= _ONE << uint32(CallConfigIndex.AllowAllocateValueFailure);
        }
    }

    function decodeCallConfig(uint32 encodedCallConfig) internal pure returns (CallConfig memory callConfig) {
        callConfig = CallConfig({
            userNoncesSequential: needsSequentialUserNonces(encodedCallConfig),
            dappNoncesSequential: needsSequentialDAppNonces(encodedCallConfig),
            requirePreOps: needsPreOpsCall(encodedCallConfig),
            trackPreOpsReturnData: needsPreOpsReturnData(encodedCallConfig),
            trackUserReturnData: needsUserReturnData(encodedCallConfig),
            delegateUser: needsDelegateUser(encodedCallConfig),
            requirePreSolver: needsPreSolverCall(encodedCallConfig),
            requirePostSolver: needsPostSolverCall(encodedCallConfig),
            requirePostOps: needsPostOpsCall(encodedCallConfig),
            zeroSolvers: allowsZeroSolvers(encodedCallConfig),
            reuseUserOp: allowsReuseUserOps(encodedCallConfig),
            userAuctioneer: allowsUserAuctioneer(encodedCallConfig),
            solverAuctioneer: allowsSolverAuctioneer(encodedCallConfig),
            unknownAuctioneer: allowsUnknownAuctioneer(encodedCallConfig),
            verifyCallChainHash: verifyCallChainHash(encodedCallConfig),
            forwardReturnData: forwardReturnData(encodedCallConfig),
            requireFulfillment: needsFulfillment(encodedCallConfig),
            trustedOpHash: allowsTrustedOpHash(encodedCallConfig),
            invertBidValue: invertsBidValue(encodedCallConfig),
            exPostBids: exPostBids(encodedCallConfig),
            allowAllocateValueFailure: allowAllocateValueFailure(encodedCallConfig)
        });
    }

    function needsSequentialUserNonces(uint32 callConfig) internal pure returns (bool sequential) {
        sequential = callConfig & (1 << uint32(CallConfigIndex.UserNoncesSequential)) != 0;
    }

    function needsSequentialDAppNonces(uint32 callConfig) internal pure returns (bool sequential) {
        sequential = callConfig & (1 << uint32(CallConfigIndex.DAppNoncesSequential)) != 0;
    }

    function needsPreOpsCall(uint32 callConfig) internal pure returns (bool needsPreOps) {
        needsPreOps = callConfig & (1 << uint32(CallConfigIndex.RequirePreOps)) != 0;
    }

    function needsPreOpsReturnData(uint32 callConfig) internal pure returns (bool needsReturnData) {
        needsReturnData = callConfig & (1 << uint32(CallConfigIndex.TrackPreOpsReturnData)) != 0;
    }

    function needsUserReturnData(uint32 callConfig) internal pure returns (bool needsReturnData) {
        needsReturnData = callConfig & (1 << uint32(CallConfigIndex.TrackUserReturnData)) != 0;
    }

    function needsDelegateUser(uint32 callConfig) internal pure returns (bool delegateUser) {
        delegateUser = callConfig & (1 << uint32(CallConfigIndex.DelegateUser)) != 0;
    }

    function needsPreSolverCall(uint32 callConfig) internal pure returns (bool needsPreSolver) {
        needsPreSolver = callConfig & (1 << uint32(CallConfigIndex.RequirePreSolver)) != 0;
    }

    function needsPostSolverCall(uint32 callConfig) internal pure returns (bool needsPostSolver) {
        needsPostSolver = callConfig & (1 << uint32(CallConfigIndex.RequirePostSolver)) != 0;
    }

    function needsPostOpsCall(uint32 callConfig) internal pure returns (bool needsPostOps) {
        needsPostOps = callConfig & (1 << uint32(CallConfigIndex.RequirePostOpsCall)) != 0;
    }

    function allowsZeroSolvers(uint32 callConfig) internal pure returns (bool zeroSolvers) {
        zeroSolvers = callConfig & (1 << uint32(CallConfigIndex.ZeroSolvers)) != 0;
    }

    function allowsReuseUserOps(uint32 callConfig) internal pure returns (bool reuseUserOp) {
        reuseUserOp = callConfig & (1 << uint32(CallConfigIndex.ReuseUserOp)) != 0;
    }

    function allowsUserAuctioneer(uint32 callConfig) internal pure returns (bool userAuctioneer) {
        userAuctioneer = callConfig & (1 << uint32(CallConfigIndex.UserAuctioneer)) != 0;
    }

    function allowsSolverAuctioneer(uint32 callConfig) internal pure returns (bool userAuctioneer) {
        userAuctioneer = callConfig & (1 << uint32(CallConfigIndex.SolverAuctioneer)) != 0;
    }

    function allowsUnknownAuctioneer(uint32 callConfig) internal pure returns (bool unknownAuctioneer) {
        unknownAuctioneer = callConfig & (1 << uint32(CallConfigIndex.UnknownAuctioneer)) != 0;
    }

    function verifyCallChainHash(uint32 callConfig) internal pure returns (bool verify) {
        verify = callConfig & (1 << uint32(CallConfigIndex.VerifyCallChainHash)) != 0;
    }

    function forwardReturnData(uint32 callConfig) internal pure returns (bool) {
        return callConfig & (1 << uint32(CallConfigIndex.ForwardReturnData)) != 0;
    }

    function needsFulfillment(uint32 callConfig) internal pure returns (bool) {
        return callConfig & (1 << uint32(CallConfigIndex.RequireFulfillment)) != 0;
    }

    function allowsTrustedOpHash(uint32 callConfig) internal pure returns (bool) {
        return callConfig & (1 << uint32(CallConfigIndex.TrustedOpHash)) != 0;
    }

    function invertsBidValue(uint32 callConfig) internal pure returns (bool) {
        return callConfig & (1 << uint32(CallConfigIndex.InvertBidValue)) != 0;
    }

    function exPostBids(uint32 callConfig) internal pure returns (bool) {
        return callConfig & (1 << uint32(CallConfigIndex.ExPostBids)) != 0;
    }

    function allowAllocateValueFailure(uint32 callConfig) internal pure returns (bool) {
        return callConfig & (1 << uint32(CallConfigIndex.AllowAllocateValueFailure)) != 0;
    }
}

File 13 of 35 : SafetyBits.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "../types/LockTypes.sol";

// NOTE: No user transfers allowed during AllocateValue
uint8 constant SAFE_USER_TRANSFER = uint8(
    1 << (uint8(ExecutionPhase.PreOps)) | 1 << (uint8(ExecutionPhase.UserOperation))
        | 1 << (uint8(ExecutionPhase.PreSolver)) | 1 << (uint8(ExecutionPhase.PostSolver))
        | 1 << (uint8(ExecutionPhase.PostOps))
);

// NOTE: No Dapp transfers allowed during UserOperation
uint8 constant SAFE_DAPP_TRANSFER = uint8(
    1 << (uint8(ExecutionPhase.PreOps)) | 1 << (uint8(ExecutionPhase.PreSolver))
        | 1 << (uint8(ExecutionPhase.PostSolver)) | 1 << (uint8(ExecutionPhase.AllocateValue))
        | 1 << (uint8(ExecutionPhase.PostOps))
);

library SafetyBits {
    function setAndPack(Context memory self, ExecutionPhase phase) internal pure returns (bytes memory packedCtx) {
        self.phase = uint8(phase);
        packedCtx = abi.encodePacked(
            self.bundler,
            self.solverSuccessful,
            self.paymentsSuccessful,
            self.solverIndex,
            self.solverCount,
            uint8(phase),
            self.solverOutcome,
            self.bidFind,
            self.isSimulation,
            uint8(1) // callDepth
        );
    }
}

File 14 of 35 : IL2GasCalculator.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

interface IL2GasCalculator {
    /// @notice Calculate the cost of calldata in ETH on a L2 with a different fee structure than mainnet
    function getCalldataCost(uint256 calldataLength) external view returns (uint256 calldataCost);
    /// @notice Gets the cost of initial gas used for a transaction with a different calldata fee than mainnet
    function initialGasUsed(uint256 calldataLength) external view returns (uint256 gasUsed);
}

File 15 of 35 : IDAppControl.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "../types/UserOperation.sol";
import "../types/SolverOperation.sol";
import "../types/ConfigTypes.sol";

interface IDAppControl {
    function preOpsCall(UserOperation calldata userOp) external payable returns (bytes memory);

    function preSolverCall(SolverOperation calldata solverOp, bytes calldata returnData) external payable;

    function postSolverCall(SolverOperation calldata solverOp, bytes calldata returnData) external payable;

    function postOpsCall(bool solved, bytes calldata data) external payable;

    function allocateValueCall(address bidToken, uint256 bidAmount, bytes calldata data) external;

    function getDAppConfig(UserOperation calldata userOp) external view returns (DAppConfig memory dConfig);

    function getCallConfig() external view returns (CallConfig memory callConfig);

    function getBidFormat(UserOperation calldata userOp) external view returns (address bidToken);

    function getBidValue(SolverOperation calldata solverOp) external view returns (uint256);

    function getDAppSignatory() external view returns (address governanceAddress);

    function requireSequentialUserNonces() external view returns (bool isSequential);

    function requireSequentialDAppNonces() external view returns (bool isSequential);

    function preOpsDelegated() external view returns (bool delegated);

    function userDelegated() external view returns (bool delegated);

    function allocatingDelegated() external view returns (bool delegated);

    function verificationDelegated() external view returns (bool delegated);

    function CALL_CONFIG() external view returns (uint32);

    function transferGovernance(address newGovernance) external;

    function acceptGovernance() external;
}

File 16 of 35 : AtlETH.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol";
import { SafeCast } from "openzeppelin-contracts/contracts/utils/math/SafeCast.sol";
import { Permit69 } from "./Permit69.sol";
import "../types/EscrowTypes.sol";

/// @author FastLane Labs
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract AtlETH is Permit69 {
    constructor(
        uint256 escrowDuration,
        uint256 atlasSurchargeRate,
        uint256 bundlerSurchargeRate,
        address verification,
        address simulator,
        address initialSurchargeRecipient,
        address l2GasCalculator
    )
        Permit69(
            escrowDuration,
            atlasSurchargeRate,
            bundlerSurchargeRate,
            verification,
            simulator,
            initialSurchargeRecipient,
            l2GasCalculator
        )
    { }

    /*//////////////////////////////////////////////////////////////
                                ATLETH
    //////////////////////////////////////////////////////////////*/

    /// @notice Returns the unbonded AtlETH balance of the specified account.
    /// @param account The address for which to query the unbonded AtlETH balance.
    /// @return The unbonded AtlETH balance of the specified account.
    function balanceOf(address account) external view returns (uint256) {
        return uint256(s_balanceOf[account].balance);
    }

    /// @notice Returns the bonded AtlETH balance of the specified account.
    /// @param account The address for which to query the bonded AtlETH balance.
    /// @return The bonded AtlETH balance of the specified account.
    function balanceOfBonded(address account) external view returns (uint256) {
        return uint256(S_accessData[account].bonded);
    }

    /// @notice Returns the unbonding AtlETH balance of the specified account.
    /// @param account The address for which to query the unbonding AtlETH balance.
    /// @return The unbonding AtlETH balance of the specified account.
    function balanceOfUnbonding(address account) external view returns (uint256) {
        return uint256(s_balanceOf[account].unbonding);
    }

    /// @notice Returns the last active block of the specified account in the escrow contract.
    /// @param account The address for which to query the last active block.
    /// @return The last active block of the specified account in the escrow contract.
    function accountLastActiveBlock(address account) external view returns (uint256) {
        return uint256(S_accessData[account].lastAccessedBlock);
    }

    /// @notice Returns the block number at which the unbonding process of the specified account will be completed.
    /// @param account The address for which to query the completion block of unbonding.
    /// @return The block number at which the unbonding process of the specified account will be completed.
    function unbondingCompleteBlock(address account) external view returns (uint256) {
        uint256 _lastAccessedBlock = uint256(S_accessData[account].lastAccessedBlock);
        if (_lastAccessedBlock == 0) return 0;
        return _lastAccessedBlock + ESCROW_DURATION;
    }

    /// @notice Deposits ETH to receive atlETH tokens in return.
    /// @dev Mints atlETH tokens to the caller in exchange for the deposited ETH.
    function deposit() external payable {
        _mint(msg.sender, msg.value);
    }

    /// @notice Redeems atlETH tokens for ETH.
    /// @dev Burns the specified amount of atlETH tokens from the caller's balance and transfers the equivalent amount
    /// of ETH to the caller.
    /// @param amount The amount of atlETH tokens to redeem for ETH.
    function withdraw(uint256 amount) external {
        _checkIfUnlocked();
        _burn(msg.sender, amount);
        SafeTransferLib.safeTransferETH(msg.sender, amount);
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    /// @notice Mints new atlETH tokens and assigns them to the specified account.
    /// @param to The address to which the newly minted atlETH tokens will be assigned.
    /// @param amount The amount of atlETH tokens to mint and assign to the specified account.
    function _mint(address to, uint256 amount) internal {
        S_totalSupply += amount;
        s_balanceOf[to].balance += SafeCast.toUint112(amount);
        emit Mint(to, amount);
    }

    /// @notice Burns atlETH tokens from the specified account.
    /// @param from The address from which the atlETH tokens will be burned.
    /// @param amount The amount of atlETH tokens to burn from the specified account.
    function _burn(address from, uint256 amount) internal {
        _deduct(from, amount);
        S_totalSupply -= amount;
        emit Burn(from, amount);
    }

    /// @notice Deducts atlETH tokens from the specified account.
    /// @dev This function deducts the specified amount of atlETH tokens from the balance of the specified account.
    /// If the deduction results in a negative balance, it handles the shortfall differently depending on whether the
    /// account has passed the unbonding lock period. If the account has passed the lock period, the shortfall is
    /// considered as unbonding, and the total supply is adjusted accordingly. Otherwise, if the account is still within
    /// the lock period, the function reverts due to insufficient balance for deduction.
    /// @param account The address from which to deduct atlETH tokens.
    /// @param amount The amount of atlETH tokens to deduct from the specified account.
    function _deduct(address account, uint256 amount) internal {
        uint112 _amt = SafeCast.toUint112(amount);

        EscrowAccountBalance storage s_aData = s_balanceOf[account];

        uint112 _balance = s_aData.balance;

        if (_amt <= _balance) {
            s_aData.balance = _balance - _amt;
        } else if (block.number > S_accessData[account].lastAccessedBlock + ESCROW_DURATION) {
            uint112 _shortfall = _amt - _balance;
            s_aData.balance = 0;
            s_aData.unbonding -= _shortfall; // underflow here to revert if insufficient balance

            uint256 _shortfall256 = uint256(_shortfall);
            S_totalSupply += _shortfall256; // add the released supply back to atleth.
            S_bondedTotalSupply -= _shortfall256; // subtract the unbonded, freed amount
        } else {
            // Reverts because amount > account's balance
            revert InsufficientBalanceForDeduction(uint256(_balance), amount);
        }
    }

    /*//////////////////////////////////////////////////////////////
                    EXTERNAL BOND/UNBOND LOGIC
    //////////////////////////////////////////////////////////////*/

    /// @notice Puts a "hold" on a solver's AtlETH, enabling it to be used in Atlas transactions.
    /// @dev This function locks the specified amount of AtlETH tokens for the sender, making them bonded.
    /// Bonded AtlETH tokens must first be unbonded before they can be transferred or withdrawn.
    /// @param amount The amount of AtlETH tokens to bond.
    function bond(uint256 amount) external {
        _bond(msg.sender, amount);
    }

    /// @notice Deposits the caller's ETH and mints AtlETH, then bonds a specified amount of that AtlETH.
    /// @param amountToBond The amount of AtlETH tokens to bond after the deposit.
    function depositAndBond(uint256 amountToBond) external payable {
        _mint(msg.sender, msg.value);
        _bond(msg.sender, amountToBond);
    }

    /// @notice Starts the unbonding wait time for the specified amount of AtlETH tokens.
    /// @dev This function initiates the unbonding process for the specified amount of AtlETH tokens
    /// held by the sender. Unbonding AtlETH tokens can still be used by solvers while the unbonding
    /// process is ongoing, but adjustments may be made at withdrawal to ensure solvency.
    /// @param amount The amount of AtlETH tokens to unbond.
    function unbond(uint256 amount) external {
        _checkIfUnlocked();
        _unbond(msg.sender, amount);
    }

    /// @notice Redeems the specified amount of AtlETH tokens for withdrawal.
    /// @param amount The amount of AtlETH tokens to redeem for withdrawal.
    function redeem(uint256 amount) external {
        _checkIfUnlocked();
        _redeem(msg.sender, amount);
    }

    /*//////////////////////////////////////////////////////////////
                    INTERNAL BOND/UNBOND LOGIC
    //////////////////////////////////////////////////////////////*/

    /// @notice Puts a hold on a solver's AtlETH tokens, enabling them to be used in Atlas transactions.
    /// @dev This internal function puts a hold on a solver's AtlETH tokens, enabling them to be used
    /// in Atlas transactions. The specified amount of AtlETH tokens is deducted from the owner's balance
    /// and added to the bonded balance. The total supply and bonded total supply are updated accordingly.
    /// @param owner The address of the account to put a hold on AtlETH tokens for.
    /// @param amount The amount of AtlETH tokens to put a hold on.
    function _bond(address owner, uint256 amount) internal {
        uint112 _amt = SafeCast.toUint112(amount);

        s_balanceOf[owner].balance -= _amt;
        S_totalSupply -= amount;

        S_accessData[owner].bonded += _amt;
        S_bondedTotalSupply += amount;

        emit Bond(owner, amount);
    }

    /// @notice Starts the unbonding wait time for a specified amount of AtlETH tokens.
    /// @dev This internal function starts the unbonding wait time for a specified amount of AtlETH tokens.
    /// The specified amount of AtlETH tokens is deducted from the owner's bonded balance and added to the
    /// unbonding balance. The last accessed block for the owner is updated to the current block number.
    /// @param owner The address of the account to start the unbonding wait time for.
    /// @param amount The amount of AtlETH tokens to start the unbonding wait time for.
    function _unbond(address owner, uint256 amount) internal {
        uint112 _amt = SafeCast.toUint112(amount);

        // totalSupply and totalBondedSupply are unaffected; continue to count the
        // unbonding amount as bonded total supply since it is still inaccessible
        // for atomic xfer.

        EscrowAccountAccessData storage s_aData = S_accessData[owner];

        s_aData.bonded -= _amt;
        s_aData.lastAccessedBlock = uint32(block.number);

        s_balanceOf[owner].unbonding += _amt;

        emit Unbond(owner, amount, block.number + ESCROW_DURATION + 1);
    }

    /// @notice Redeems the specified amount of AtlETH tokens for withdrawal.
    /// @dev This function allows the owner to redeem a specified amount of AtlETH tokens
    /// for withdrawal. If the unbonding process is active for the specified account, the
    /// function will revert. Otherwise, the specified amount of AtlETH tokens will be added
    /// back to the account's balance, and the total supply will be updated accordingly.
    /// @param owner The address of the account redeeming AtlETH tokens for withdrawal.
    /// @param amount The amount of AtlETH tokens to redeem for withdrawal.
    function _redeem(address owner, uint256 amount) internal {
        if (block.number <= uint256(S_accessData[owner].lastAccessedBlock) + ESCROW_DURATION) {
            revert EscrowLockActive();
        }

        uint112 _amt = SafeCast.toUint112(amount);

        EscrowAccountBalance storage s_bData = s_balanceOf[owner];

        s_bData.unbonding -= _amt;
        S_bondedTotalSupply -= amount;

        s_bData.balance += _amt;
        S_totalSupply += amount;

        emit Redeem(owner, amount);
    }

    /// @notice Allows the current surcharge recipient to withdraw the accumulated surcharge. NOTE: If the only ETH in
    /// Atlas is the surcharge, be mindful that withdrawing this ETH may limit solvers' liquidity to flashloan ETH from
    /// Atlas in their solverOps.
    /// @dev This function can only be called by the current surcharge recipient.
    /// It transfers the accumulated surcharge amount to the surcharge recipient's address.
    function withdrawSurcharge() external {
        _onlySurchargeRecipient();

        uint256 _paymentAmount = S_cumulativeSurcharge;
        S_cumulativeSurcharge = 0; // Clear before transfer to prevent reentrancy
        SafeTransferLib.safeTransferETH(msg.sender, _paymentAmount);
        emit SurchargeWithdrawn(msg.sender, _paymentAmount);
    }

    /// @notice Starts the transfer of the surcharge recipient designation to a new address.
    /// @dev This function can only be called by the current surcharge recipient.
    /// It sets the `pendingSurchargeRecipient` to the specified `newRecipient` address,
    /// allowing the new recipient to claim the surcharge recipient designation by calling `becomeSurchargeRecipient`.
    /// If the caller is not the current surcharge recipient, it reverts with an `InvalidAccess` error.
    /// @param newRecipient The address of the new surcharge recipient.
    function transferSurchargeRecipient(address newRecipient) external {
        _onlySurchargeRecipient();

        address _surchargeRecipient = S_surchargeRecipient;

        S_pendingSurchargeRecipient = newRecipient;
        emit SurchargeRecipientTransferStarted(_surchargeRecipient, newRecipient);
    }

    /// @notice Finalizes the transfer of the surcharge recipient designation to a new address.
    /// @dev This function can only be called by the pending surcharge recipient,
    /// and it completes the transfer of the surcharge recipient designation to the address
    /// stored in `pendingSurchargeRecipient`.
    /// If the caller is not the pending surcharge recipient, it reverts with an `InvalidAccess` error.
    function becomeSurchargeRecipient() external {
        if (msg.sender != S_pendingSurchargeRecipient) {
            revert InvalidAccess();
        }

        S_surchargeRecipient = msg.sender;
        S_pendingSurchargeRecipient = address(0);
        emit SurchargeRecipientTransferred(msg.sender);
    }

    function _checkIfUnlocked() internal view {
        if (!_isUnlocked()) revert InvalidLockState();
    }
}

File 17 of 35 : IExecutionEnvironment.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "../types/SolverOperation.sol";
import "../types/UserOperation.sol";
import "../types/ConfigTypes.sol";
import "../types/EscrowTypes.sol";

interface IExecutionEnvironment {
    function preOpsWrapper(UserOperation calldata userOp) external returns (bytes memory preOpsData);

    function userWrapper(UserOperation calldata userOp) external payable returns (bytes memory userReturnData);

    function postOpsWrapper(bool solved, bytes calldata returnData) external;

    function solverPreTryCatch(
        uint256 bidAmount,
        SolverOperation calldata solverOp,
        bytes calldata returnData
    )
        external
        returns (SolverTracker memory solverTracker);

    function solverPostTryCatch(
        SolverOperation calldata solverOp,
        bytes calldata returnData,
        SolverTracker memory solverTracker
    )
        external
        returns (SolverTracker memory);

    function allocateValue(
        address bidToken,
        uint256 bidAmount,
        bytes memory returnData
    )
        external
        returns (bool allocateValueSucceeded);

    function getUser() external pure returns (address user);
    function getControl() external pure returns (address control);
    function getConfig() external pure returns (uint32 config);
    function getEscrow() external view returns (address escrow);

    function withdrawERC20(address token, uint256 amount) external;
    function withdrawEther(uint256 amount) external;
}

File 18 of 35 : IAtlas.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "../types/SolverOperation.sol";
import "../types/UserOperation.sol";
import "../types/DAppOperation.sol";
import "../types/LockTypes.sol";

interface IAtlas {
    // Atlas.sol
    function metacall(
        UserOperation calldata userOp,
        SolverOperation[] calldata solverOps,
        DAppOperation calldata dAppOp,
        address gasRefundBeneficiary
    )
        external
        payable
        returns (bool auctionWon);

    // Factory.sol
    function createExecutionEnvironment(
        address user,
        address control
    )
        external
        returns (address executionEnvironment);
    function getExecutionEnvironment(
        address user,
        address control
    )
        external
        view
        returns (address executionEnvironment, uint32 callConfig, bool exists);

    // AtlETH.sol
    function balanceOf(address account) external view returns (uint256);
    function balanceOfBonded(address account) external view returns (uint256);
    function balanceOfUnbonding(address account) external view returns (uint256);
    function accountLastActiveBlock(address account) external view returns (uint256);
    function unbondingCompleteBlock(address account) external view returns (uint256);
    function deposit() external payable;
    function withdraw(uint256 amount) external;
    function bond(uint256 amount) external;
    function depositAndBond(uint256 amountToBond) external payable;
    function unbond(uint256 amount) external;
    function redeem(uint256 amount) external;

    function withdrawSurcharge() external;
    function transferSurchargeRecipient(address newRecipient) external;
    function becomeSurchargeRecipient() external;
    function setSurchargeRates(uint128 newAtlasRate, uint128 newBundlerRate) external;

    // Permit69.sol
    function transferUserERC20(
        address token,
        address destination,
        uint256 amount,
        address user,
        address control
    )
        external;
    function transferDAppERC20(
        address token,
        address destination,
        uint256 amount,
        address user,
        address control
    )
        external;

    // GasAccounting.sol
    function contribute() external payable;
    function borrow(uint256 amount) external payable;
    function shortfall() external view returns (uint256);
    function reconcile(uint256 maxApprovedGasSpend) external payable returns (uint256 owed);

    // SafetyLocks.sol
    function isUnlocked() external view returns (bool);

    // Storage.sol
    function VERIFICATION() external view returns (address);
    function SIMULATOR() external view returns (address);
    function L2_GAS_CALCULATOR() external view returns (address);
    function ESCROW_DURATION() external view returns (uint256);

    function solverLockData() external view returns (address currentSolver, bool calledBack, bool fulfilled);
    function totalSupply() external view returns (uint256);
    function bondedTotalSupply() external view returns (uint256);
    function accessData(address account)
        external
        view
        returns (
            uint112 bonded,
            uint32 lastAccessedBlock,
            uint24 auctionWins,
            uint24 auctionFails,
            uint64 totalGasValueUsed
        );
    function solverOpHashes(bytes32 opHash) external view returns (bool);
    function lock() external view returns (address activeEnvironment, uint32 callConfig, uint8 phase);
    function solverLock() external view returns (uint256);
    function cumulativeSurcharge() external view returns (uint256);
    function surchargeRecipient() external view returns (address);
    function pendingSurchargeRecipient() external view returns (address);
    function atlasSurchargeRate() external view returns (uint256);
    function bundlerSurchargeRate() external view returns (uint256);
}

File 19 of 35 : ISolverContract.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "../types/SolverOperation.sol";

interface ISolverContract {
    function atlasSolverCall(
        address solverOpFrom,
        address executionEnvironment,
        address bidToken,
        uint256 bidAmount,
        bytes calldata solverOpData,
        bytes calldata extraReturnData
    )
        external
        payable;
}

File 20 of 35 : IAtlasVerification.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "../types/UserOperation.sol";
import "../types/ConfigTypes.sol";
import "../types/DAppOperation.sol";
import "../types/SolverOperation.sol";
import "../types/EscrowTypes.sol";
import "../types/ValidCalls.sol";

interface IAtlasVerification {
    // AtlasVerification.sol
    function validateCalls(
        DAppConfig calldata dConfig,
        UserOperation calldata userOp,
        SolverOperation[] calldata solverOps,
        DAppOperation calldata dAppOp,
        uint256 msgValue,
        address msgSender,
        bool isSimulation
    )
        external
        returns (ValidCallsResult);
    function verifySolverOp(
        SolverOperation calldata solverOp,
        bytes32 userOpHash,
        uint256 userMaxFeePerGas,
        address bundler,
        bool allowsTrustedOpHash
    )
        external
        view
        returns (uint256 result);
    function verifyCallConfig(uint32 callConfig) external view returns (ValidCallsResult);
    function getUserOperationHash(UserOperation calldata userOp) external view returns (bytes32 hash);
    function getUserOperationPayload(UserOperation calldata userOp) external view returns (bytes32 payload);
    function getSolverPayload(SolverOperation calldata solverOp) external view returns (bytes32 payload);
    function getDAppOperationPayload(DAppOperation calldata dAppOp) external view returns (bytes32 payload);
    function getDomainSeparator() external view returns (bytes32 domainSeparator);

    // NonceManager.sol
    function getUserNextNonce(address user, bool sequential) external view returns (uint256 nextNonce);
    function getUserNextNonSeqNonceAfter(address user, uint256 refNonce) external view returns (uint256);
    function getDAppNextNonce(address dApp) external view returns (uint256 nextNonce);
    function userSequentialNonceTrackers(address account) external view returns (uint256 lastUsedSeqNonce);
    function dAppSequentialNonceTrackers(address account) external view returns (uint256 lastUsedSeqNonce);
    function userNonSequentialNonceTrackers(
        address account,
        uint248 wordIndex
    )
        external
        view
        returns (uint256 bitmap);

    // DAppIntegration.sol
    function initializeGovernance(address control) external;
    function addSignatory(address control, address signatory) external;
    function removeSignatory(address control, address signatory) external;
    function changeDAppGovernance(address oldGovernance, address newGovernance) external;
    function disableDApp(address control) external;
    function getGovFromControl(address control) external view returns (address);
    function isDAppSignatory(address control, address signatory) external view returns (bool);
    function signatories(bytes32 key) external view returns (bool);
    function dAppSignatories(address control) external view returns (address[] memory);
}

File 21 of 35 : SafeCall.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/// @title SafeCall
/// @author FastLane Labs
/// @author Modified from Optimism's SafeCall lib
/// (https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/libraries/SafeCall.sol)
/// @notice Perform low level safe calls
library SafeCall {
    /// @notice Perform a low level call without copying any returndata
    /// @param _target   Address to call
    /// @param _gas      Amount of gas to pass to the call
    /// @param _value    Amount of value to pass to the call
    /// @param _calldata Calldata to pass to the call
    function safeCall(address _target, uint256 _gas, uint256 _value, bytes memory _calldata) internal returns (bool) {
        bool _success;
        assembly {
            _success :=
                call(
                    _gas, // gas
                    _target, // recipient
                    _value, // ether value
                    add(_calldata, 32), // inloc
                    mload(_calldata), // inlen
                    0, // outloc
                    0 // outlen
                )
        }
        return _success;
    }
}

File 22 of 35 : EscrowBits.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "../types/EscrowTypes.sol";

library EscrowBits {
    // Bundler's Fault - solver doesn't owe any gas refund. SolverOp isn't executed
    uint256 internal constant _NO_REFUND = (
        1 << uint256(SolverOutcome.InvalidSignature) // <- detected by verification
            | 1 << uint256(SolverOutcome.InvalidUserHash) // <- detected by verification
            | 1 << uint256(SolverOutcome.DeadlinePassedAlt) // <- detected by escrow
            | 1 << uint256(SolverOutcome.GasPriceBelowUsersAlt) // <- detected by verification
            | 1 << uint256(SolverOutcome.InvalidTo) // <- detected by verification
            | 1 << uint256(SolverOutcome.UserOutOfGas) // <- detected by escrow
            | 1 << uint256(SolverOutcome.AlteredControl) // <- detected by EE
            | 1 << uint256(SolverOutcome.AltOpHashMismatch)
    ); // <- detected by escrow

    // Solver's Fault - solver *does* owe gas refund, SolverOp isn't executed
    uint256 internal constant _PARTIAL_REFUND = (
        1 << uint256(SolverOutcome.DeadlinePassed) // <- detected by escrow
            | 1 << uint256(SolverOutcome.GasPriceOverCap) // <- detected by verification
            | 1 << uint256(SolverOutcome.InvalidSolver) // <- detected by verification
            | 1 << uint256(SolverOutcome.InvalidBidToken) // <- detected by escrow
            | 1 << uint256(SolverOutcome.PerBlockLimit) // <- detected by escrow
            | 1 << uint256(SolverOutcome.InsufficientEscrow) // <- detected by escrow
            | 1 << uint256(SolverOutcome.GasPriceBelowUsers) // <- detected by verification
            | 1 << uint256(SolverOutcome.CallValueTooHigh) // <- detected by escrow
            | 1 << uint256(SolverOutcome.PreSolverFailed)
    ); // <- detected by EE

    // Solver's Fault - solver *does* owe gas refund, SolverOp *was* executed
    uint256 internal constant _FULL_REFUND = (
        1 << uint256(SolverOutcome.SolverOpReverted) // <- detected by Escrow
            | 1 << uint256(SolverOutcome.PostSolverFailed) // <- detected by EE
            | 1 << uint256(SolverOutcome.BidNotPaid) // <- detected by EE
            | 1 << uint256(SolverOutcome.InvertedBidExceedsCeiling) // <- detected by EE
            | 1 << uint256(SolverOutcome.BalanceNotReconciled) // <- detected by Escrow
            | 1 << uint256(SolverOutcome.CallbackNotCalled) // <- detected by Escrow
            | 1 << uint256(SolverOutcome.EVMError)
    ); // <- default if err by EE

    function canExecute(uint256 result) internal pure returns (bool) {
        return (result == 0);
    }

    // NOTE: PartialRefunds mean that the tx isn't executed but solver is still liable
    // for some gas costs.
    function partialRefund(uint256 result) internal pure returns (bool) {
        return ((result & _PARTIAL_REFUND) != 0);
    }

    function executionSuccessful(uint256 result) internal pure returns (bool) {
        return (result == 0);
    }

    function executedWithError(uint256 result) internal pure returns (bool) {
        return (result & _FULL_REFUND) != 0;
    }

    function bundlersFault(uint256 result) internal pure returns (bool) {
        // Only update solver escrow if failure is not due to bundler's fault
        // returns true if bundler blamed and no solver refund required
        return (result & _NO_REFUND != 0);
    }
}

File 23 of 35 : AccountingMath.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

library AccountingMath {
    uint256 internal constant _MAX_BUNDLER_REFUND_RATE = 8_000_000; // out of 10_000_000 = 80%
    uint256 internal constant _SOLVER_GAS_LIMIT_BUFFER_PERCENTAGE = 500_000; // out of 10_000_000 = 5%
    uint256 internal constant _SCALE = 10_000_000; // 10_000_000 / 10_000_000 = 100%
    uint256 internal constant _FIXED_GAS_OFFSET = 120_000;

    function withSurcharge(uint256 amount, uint256 surchargeRate) internal pure returns (uint256 adjustedAmount) {
        adjustedAmount = amount * (_SCALE + surchargeRate) / _SCALE;
    }

    function withoutSurcharge(uint256 amount, uint256 surchargeRate) internal pure returns (uint256 unadjustedAmount) {
        unadjustedAmount = amount * _SCALE / (_SCALE + surchargeRate);
    }

    function withSurcharges(
        uint256 amount,
        uint256 atlasSurchargeRate,
        uint256 bundlerSurchargeRate
    )
        internal
        pure
        returns (uint256 adjustedAmount)
    {
        adjustedAmount = amount * (_SCALE + atlasSurchargeRate + bundlerSurchargeRate) / _SCALE;
    }

    // gets the Atlas surcharge from an unadjusted amount
    function getSurcharge(
        uint256 unadjustedAmount,
        uint256 surchargeRate
    )
        internal
        pure
        returns (uint256 surchargeAmount)
    {
        surchargeAmount = unadjustedAmount * surchargeRate / _SCALE;
    }

    function getPortionFromTotalSurcharge(
        uint256 totalSurcharge,
        uint256 targetSurchargeRate,
        uint256 totalSurchargeRate
    )
        internal
        pure
        returns (uint256 surchargePortion)
    {
        surchargePortion = totalSurcharge * targetSurchargeRate / totalSurchargeRate;
    }

    // NOTE: This max should only be applied when there are no winning solvers.
    // Set to 80% of the metacall gas cost, because the remaining 20% can be collected through storage refunds.
    function maxBundlerRefund(uint256 metacallGasCost) internal pure returns (uint256 maxRefund) {
        maxRefund = metacallGasCost * _MAX_BUNDLER_REFUND_RATE / _SCALE;
    }

    function solverGasLimitScaledDown(
        uint256 solverOpGasLimit,
        uint256 dConfigGasLimit
    )
        internal
        pure
        returns (uint256 gasLimit)
    {
        gasLimit = (solverOpGasLimit < dConfigGasLimit ? solverOpGasLimit : dConfigGasLimit) * _SCALE
            / (_SCALE + _SOLVER_GAS_LIMIT_BUFFER_PERCENTAGE);
    }
}

File 24 of 35 : EscrowTypes.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

// bonded = total - unbonding
struct EscrowAccountBalance {
    uint112 balance;
    uint112 unbonding;
}

struct EscrowAccountAccessData {
    uint112 bonded;
    uint32 lastAccessedBlock;
    uint24 auctionWins;
    uint24 auctionFails;
    uint64 totalGasValueUsed; // The cumulative ETH value spent on gas in metacalls. Measured in gwei.
}

// Additional struct to avoid Stack Too Deep while tracking variables related to the solver call.
struct SolverTracker {
    uint256 bidAmount;
    uint256 floor;
    uint256 ceiling;
    bool etherIsBidToken;
    bool invertsBidValue;
}

/// @title SolverOutcome
/// @notice Enum for SolverOutcome
/// @dev Multiple SolverOutcomes can be used to represent the outcome of a solver call
/// @dev Typical usage looks like solverOutcome = (1 << SolverOutcome.InvalidSignature) | (1 <<
/// SolverOutcome.InvalidUserHash) to indicate SolverOutcome.InvalidSignature and SolverOutcome.InvalidUserHash
enum SolverOutcome {
    // No Refund (relay error or hostile user)
    InvalidSignature,
    InvalidUserHash,
    DeadlinePassedAlt,
    GasPriceBelowUsersAlt,
    InvalidTo,
    UserOutOfGas,
    AlteredControl,
    AltOpHashMismatch,
    // Partial Refund but no execution
    DeadlinePassed,
    GasPriceOverCap,
    InvalidSolver,
    InvalidBidToken,
    PerBlockLimit, // solvers can only send one tx per block
    // if they sent two we wouldn't be able to flag builder censorship
    InsufficientEscrow,
    GasPriceBelowUsers,
    CallValueTooHigh,
    PreSolverFailed,
    // execution, with Full Refund
    SolverOpReverted,
    PostSolverFailed,
    BidNotPaid,
    InvertedBidExceedsCeiling,
    BalanceNotReconciled,
    CallbackNotCalled,
    EVMError
}

File 25 of 35 : FactoryLib.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import { Mimic } from "../common/Mimic.sol";
import { AtlasEvents } from "../types/AtlasEvents.sol";

// NOTE: Do not call these functions directly. This contract should only ever be delegatecalled by the Atlas contract.

contract FactoryLib {
    address public immutable EXECUTION_ENV_TEMPLATE;

    /// @notice Initializes a new Factory contract instance by setting the immutable salt for deterministic deployment
    /// of Execution Environments and storing the execution template address.
    /// @dev The Execution Environment Template must be separately deployed using the same calculated salt.
    /// @param executionTemplate Address of the pre-deployed execution template contract for creating Execution
    /// Environment instances.
    constructor(address executionTemplate) {
        EXECUTION_ENV_TEMPLATE = executionTemplate;
    }

    /// @notice Deploys a new execution environment or retrieves the address of an existing one based on the DApp
    /// control, user, and configuration.
    /// @dev Uses the `create2` opcode for deterministic deployment, allowing the calculation of the execution
    /// environment's address before deployment. The deployment uses a combination of the DAppControl address, user
    /// address, call configuration, and a unique salt to ensure the uniqueness and predictability of the environment's
    /// address.
    /// @param user The address of the user for whom the execution environment is being set.
    /// @param control The address of the DAppControl contract providing the operational context.
    /// @param callConfig CallConfig settings of the DAppControl contract.
    /// @return executionEnvironment The address of the newly created or already existing execution environment.
    function getOrCreateExecutionEnvironment(
        address user,
        address control,
        uint32 callConfig,
        bytes32 salt
    )
        public
        payable
        returns (address executionEnvironment)
    {
        bytes memory _creationCode = _getMimicCreationCode({ user: user, control: control, callConfig: callConfig });

        executionEnvironment = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(bytes1(0xff), address(this), salt, keccak256(abi.encodePacked(_creationCode)))
                    )
                )
            )
        );

        if (executionEnvironment.code.length == 0) {
            assembly {
                executionEnvironment := create2(0, add(_creationCode, 32), mload(_creationCode), salt)
            }
            emit AtlasEvents.ExecutionEnvironmentCreated(user, executionEnvironment);
        }
    }

    /// @notice Generates the address of a user's execution environment affected by deprecated callConfig changes in the
    /// DAppControl.
    /// @dev Calculates the deterministic address of the execution environment based on the user, control,
    /// callConfig, and controlCodeHash, ensuring consistency across changes in callConfig.
    /// @param user The address of the user for whom the execution environment's address is being generated.
    /// @param control The address of the DAppControl contract associated with the execution environment.
    /// @param callConfig The configuration flags defining the behavior of the execution environment.
    /// @return executionEnvironment The address of the user's execution environment.
    function getExecutionEnvironmentCustom(
        address user,
        address control,
        uint32 callConfig,
        bytes32 salt
    )
        public
        view
        returns (address executionEnvironment)
    {
        bytes memory _creationCode = _getMimicCreationCode({ user: user, control: control, callConfig: callConfig });

        executionEnvironment = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(bytes1(0xff), address(this), salt, keccak256(abi.encodePacked(_creationCode)))
                    )
                )
            )
        );
    }

    /// @notice Generates the creation code for the execution environment contract.
    /// @param control The address of the DAppControl contract associated with the execution environment.
    /// @param callConfig The configuration flags defining the behavior of the execution environment.
    /// @param user The address of the user for whom the execution environment is being created, contributing to the
    /// uniqueness of the creation code.
    /// @return creationCode The bytecode representing the creation code of the execution environment contract.
    function _getMimicCreationCode(
        address user,
        address control,
        uint32 callConfig
    )
        internal
        view
        returns (bytes memory creationCode)
    {
        address _executionLib = EXECUTION_ENV_TEMPLATE;
        // NOTE: Changing compiler settings or solidity versions can break this.
        creationCode = type(Mimic).creationCode;

        assembly {
            // Insert the ExecutionEnvironment "Lib" address, into the AAAA placeholder in the creation code.
            mstore(
                add(creationCode, 79),
                or(
                    and(mload(add(creationCode, 79)), not(shl(96, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))),
                    shl(96, _executionLib)
                )
            )

            // Insert the user address into the BBBB placeholder in the creation code.
            mstore(
                add(creationCode, 111),
                or(
                    and(mload(add(creationCode, 111)), not(shl(96, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))),
                    shl(96, user)
                )
            )

            // Insert the control address into the CCCC placeholder in the creation code.
            mstore(
                add(creationCode, 132),
                or(
                    and(mload(add(creationCode, 132)), not(shl(96, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))),
                    shl(96, control)
                )
            )

            // Insert the callConfig into the 2222 placeholder in the creation code.
            mstore(
                add(creationCode, 153),
                or(and(mload(add(creationCode, 153)), not(shl(224, 0xFFFFFFFF))), shl(224, callConfig))
            )
        }
    }
}

File 26 of 35 : AtlasErrors.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "./ValidCalls.sol";

contract AtlasErrors {
    // Simulator
    error SimulatorBalanceTooLow();
    error Unauthorized();
    error Unreachable();
    error NoAuctionWinner();
    error InvalidEntryFunction();
    error SimulationPassed();

    error UserSimulationFailed();
    error UserSimulationSucceeded();
    error UserUnexpectedSuccess();
    error UserNotFulfilled();

    error BidFindSuccessful(uint256 bidAmount);
    error UnexpectedNonRevert();

    error InvalidSolver();
    error BidNotPaid();
    error InvertedBidExceedsCeiling();
    error BalanceNotReconciled();
    error SolverOpReverted();
    error AlteredControl();
    error InvalidEntry();
    error CallbackNotCalled();
    error PreSolverFailed();
    error PostSolverFailed();
    error InsufficientEscrow();

    error VerificationSimFail(ValidCallsResult);
    error PreOpsSimFail();
    error UserOpSimFail();
    error SolverSimFail(uint256 solverOutcomeResult); // uint param is result returned in `verifySolverOp`
    error AllocateValueSimFail();
    error PostOpsSimFail();
    error ValidCalls(ValidCallsResult);

    // Execution Environment
    error InvalidUser();
    error InvalidTo();
    error InvalidCodeHash();
    error PreOpsDelegatecallFail();
    error UserOpValueExceedsBalance();
    error UserWrapperDelegatecallFail();
    error UserWrapperCallFail();
    error PostOpsDelegatecallFail();
    error PostOpsDelegatecallReturnedFalse();
    error AllocateValueDelegatecallFail();
    error NotEnvironmentOwner();
    error ExecutionEnvironmentBalanceTooLow();

    // Atlas
    error PreOpsFail();
    error UserOpFail();
    // error SolverFail(); // Only sim version of err is used
    error AllocateValueFail();
    error PostOpsFail();
    error InvalidAccess();

    // Escrow
    error UncoveredResult();
    error InvalidEscrowDuration();

    // AtlETH
    error EscrowLockActive();
    error InsufficientBalanceForDeduction(uint256 balance, uint256 requested);

    // DAppIntegration
    error OnlyGovernance();
    error SignatoryActive();
    error InvalidCaller();
    error InvalidDAppControl();
    error DAppNotEnabled();
    error AtlasLockActive();
    error InvalidSignatory();

    // Permit69
    error InvalidEnvironment();
    error EnvironmentMismatch();
    error InvalidLockState();

    // GasAccounting
    error LedgerFinalized(uint8 id);
    error LedgerBalancing(uint8 id);
    error MissingFunds(uint8 id);
    error InsufficientFunds();
    error NoUnfilledRequests();
    error SolverMustReconcile();
    error DoubleReconcile();
    error InvalidExecutionEnvironment(address correctEnvironment);
    error InvalidSolverFrom(address solverFrom);
    error InsufficientSolverBalance(uint256 actual, uint256 msgValue, uint256 holds, uint256 needed);
    error InsufficientAtlETHBalance(uint256 actual, uint256 needed);
    error InsufficientTotalBalance(uint256 shortfall);
    error UnbalancedAccounting();

    // SafetyLocks
    error NotInitialized();
    error AlreadyInitialized();

    // Storage
    error SurchargeRateTooHigh();

    // AtlasVerification
    error NoUnusedNonceInBitmap();

    // DAppControl
    error BothUserAndDAppNoncesCannotBeSequential();
    error BothPreOpsAndUserReturnDataCannotBeTracked();
    error InvalidControl();
    error NoDelegatecall();
    error MustBeDelegatecalled();
    error OnlyAtlas();
    error WrongPhase();
    error WrongDepth();
    error InsufficientLocalFunds();
    error NotImplemented();
    error InvertBidValueCannotBeExPostBids();
}

File 27 of 35 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }
}

File 28 of 35 : Permit69.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

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

import { SAFE_USER_TRANSFER, SAFE_DAPP_TRANSFER } from "../libraries/SafetyBits.sol";
import "../types/LockTypes.sol";
import "../types/EscrowTypes.sol";

// NOTE: Permit69 only works inside of the Atlas environment - specifically
// inside of the custom ExecutionEnvironments that each user deploys when
// interacting with Atlas in a manner controlled by the DeFi dApp.

// The name comes from the reciprocal nature of the token transfers. Both
// the user and the DAppControl can transfer tokens from the User
// and the DAppControl contracts... but only if they each have granted
// token approval to the Atlas main contract, and only during specific phases
// of the Atlas execution process.

/// @title Permit69
/// @author FastLane Labs
/// @notice Permit69 manages ERC20 approvals and transfers between Atlas and Execution Environment contracts during
/// metacall transactions.
abstract contract Permit69 is GasAccounting {
    constructor(
        uint256 escrowDuration,
        uint256 atlasSurchargeRate,
        uint256 bundlerSurchargeRate,
        address verification,
        address simulator,
        address initialSurchargeRecipient,
        address l2GasCalculator
    )
        GasAccounting(
            escrowDuration,
            atlasSurchargeRate,
            bundlerSurchargeRate,
            verification,
            simulator,
            initialSurchargeRecipient,
            l2GasCalculator
        )
    { }

    /// @notice Verifies that the caller is an authorized Execution Environment contract.
    /// @dev This function is called internally to ensure that the caller is a legitimate Execution Environment contract
    /// controlled by the current DAppControl contract. It helps prevent unauthorized access and ensures that
    /// token transfers are performed within the context of Atlas's controlled environment. The implementation of this
    /// function can be found in Atlas.sol
    /// @param environment ExecutionEnvironment address
    /// @param user The address of the user invoking the function.
    /// @param control The address of the current DAppControl contract.
    /// @param callConfig The CallConfig of the DAppControl contract of the current transaction.
    function _verifyUserControlExecutionEnv(
        address environment,
        address user,
        address control,
        uint32 callConfig
    )
        internal
        virtual
        returns (bool)
    { }

    /// @notice Transfers ERC20 tokens from a user to a destination address, only callable by the expected Execution
    /// Environment.
    /// @param token The address of the ERC20 token contract.
    /// @param destination The address to which the tokens will be transferred.
    /// @param amount The amount of tokens to transfer.
    /// @param user The address of the user invoking the function.
    /// @param control The address of the current DAppControl contract.
    function transferUserERC20(
        address token,
        address destination,
        uint256 amount,
        address user,
        address control
    )
        external
    {
        // Validate that the transfer is legitimate
        _validateTransfer({ user: user, control: control, safeExecutionPhaseSet: SAFE_USER_TRANSFER });

        // Transfer token
        SafeTransferLib.safeTransferFrom(token, user, destination, amount);
    }

    /// @notice Transfers ERC20 tokens from the DAppControl contract to a destination address, only callable by the
    /// expected Execution Environment.
    /// @param token The address of the ERC20 token contract.
    /// @param destination The address to which the tokens will be transferred.
    /// @param amount The amount of tokens to transfer.
    /// @param user The address of the user invoking the function.
    /// @param control The address of the current DAppControl contract.
    function transferDAppERC20(
        address token,
        address destination,
        uint256 amount,
        address user,
        address control
    )
        external
    {
        // Validate that the transfer is legitimate
        _validateTransfer({ user: user, control: control, safeExecutionPhaseSet: SAFE_DAPP_TRANSFER });

        // Transfer token
        SafeTransferLib.safeTransferFrom(token, control, destination, amount);
    }

    /// @notice Verifies whether the lock state allows execution in the specified safe execution phase.
    /// @param user The address of the user invoking the function.
    /// @param control The address of the current DAppControl contract.
    /// @param safeExecutionPhaseSet The set of safe execution phases.
    function _validateTransfer(address user, address control, uint8 safeExecutionPhaseSet) internal {
        (address _activeEnv, uint32 _callConfig, uint8 _currentPhase) = _lock();

        // Verify that the ExecutionEnvironment's context is correct.
        if (_activeEnv != msg.sender) {
            revert InvalidEnvironment();
        }

        // Verify that the given user and control are the owners of this ExecutionEnvironment
        if (!_verifyUserControlExecutionEnv(msg.sender, user, control, _callConfig)) {
            revert EnvironmentMismatch();
        }

        // Verify that the current phase allows for transfers
        if (1 << _currentPhase & safeExecutionPhaseSet == 0) {
            revert InvalidLockState();
        }
    }
}

File 29 of 35 : Mimic.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

contract Mimic {
    /*
    0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa is standin for the ExecutionEnvironment, which is a de facto library
    0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB is standin for the userOp.from address
    0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC is standin for the dApp control address
    0x2222 is standin for the call configuration
    These values are adjusted by the factory to match the appropriate values for the intended user/control/config.
    This happens during contract creation.

        creationCode = type(Mimic).creationCode;
        assembly {
            mstore(add(creationCode, 85), add(
                shl(96, executionLib), 
                0x73ffffffffffffffffffffff
            ))
            mstore(add(creationCode, 131), add(
                shl(96, user), 
                0x73ffffffffffffffffffffff
            ))
            mstore(add(creationCode, 152), add(
                shl(96, control), 
                add(
                    add(
                        shl(88, 0x61), 
                        shl(72, callConfig)
                    ),
                    0x7f0000000000000000
                )
            ))
        }
    */

    receive() external payable { }

    fallback(bytes calldata) external payable returns (bytes memory) {
        (bool success, bytes memory output) = address(0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa).delegatecall(
            abi.encodePacked(
                msg.data,
                address(0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB),
                address(0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC),
                uint32(0x22222222)
            )
        );
        if (!success) {
            assembly {
                revert(add(output, 32), mload(output))
            }
        }
        return output;
    }
}

File 30 of 35 : AtlasEvents.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

contract AtlasEvents {
    // Metacall
    event MetacallResult(
        address indexed bundler,
        address indexed user,
        bool solverSuccessful,
        bool disbursementSuccessful,
        uint256 ethPaidToBundler,
        uint256 netGasSurcharge
    );

    // AtlETH
    event Bond(address indexed owner, uint256 amount);
    event Unbond(address indexed owner, uint256 amount, uint256 earliestAvailable);
    event Redeem(address indexed owner, uint256 amount);
    event Mint(address indexed to, uint256 amount);
    event Burn(address indexed from, uint256 amount);

    // Escrow events
    event SolverTxResult(
        address indexed solverTo,
        address indexed solverFrom,
        address indexed dAppControl,
        address bidToken,
        uint256 bidAmount,
        bool executed,
        bool success,
        uint256 result
    );

    // Factory events
    event ExecutionEnvironmentCreated(address indexed user, address indexed executionEnvironment);

    // Surcharge events
    event SurchargeWithdrawn(address indexed to, uint256 amount);
    event SurchargeRecipientTransferStarted(address indexed currentRecipient, address indexed newRecipient);
    event SurchargeRecipientTransferred(address indexed newRecipient);

    // DAppControl events
    event GovernanceTransferStarted(address indexed previousGovernance, address indexed newGovernance);
    event GovernanceTransferred(address indexed previousGovernance, address indexed newGovernance);

    // DAppIntegration events
    event NewDAppSignatory(
        address indexed control, address indexed governance, address indexed signatory, uint32 callConfig
    );
    event RemovedDAppSignatory(
        address indexed control, address indexed governance, address indexed signatory, uint32 callConfig
    );
    event DAppGovernanceChanged(
        address indexed control, address indexed oldGovernance, address indexed newGovernance, uint32 callConfig
    );
    event DAppDisabled(address indexed control, address indexed governance, uint32 callConfig);
}

File 31 of 35 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

File 32 of 35 : GasAccounting.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol";
import { SafeCast } from "openzeppelin-contracts/contracts/utils/math/SafeCast.sol";

import { SafetyLocks } from "./SafetyLocks.sol";
import { EscrowBits } from "../libraries/EscrowBits.sol";
import { AccountingMath } from "../libraries/AccountingMath.sol";
import { SolverOperation } from "../types/SolverOperation.sol";
import { DAppConfig } from "../types/ConfigTypes.sol";
import { IL2GasCalculator } from "../interfaces/IL2GasCalculator.sol";
import "../types/EscrowTypes.sol";
import "../types/LockTypes.sol";

/// @title GasAccounting
/// @author FastLane Labs
/// @notice GasAccounting manages the accounting of gas surcharges and escrow balances for the Atlas protocol.
abstract contract GasAccounting is SafetyLocks {
    using EscrowBits for uint256;
    using AccountingMath for uint256;

    constructor(
        uint256 escrowDuration,
        uint256 atlasSurchargeRate,
        uint256 bundlerSurchargeRate,
        address verification,
        address simulator,
        address initialSurchargeRecipient,
        address l2GasCalculator
    )
        SafetyLocks(
            escrowDuration,
            atlasSurchargeRate,
            bundlerSurchargeRate,
            verification,
            simulator,
            initialSurchargeRecipient,
            l2GasCalculator
        )
    { }

    /// @notice Sets the initial accounting values for the metacall transaction.
    /// @param gasMarker The gas marker used to calculate the initial accounting values.
    function _initializeAccountingValues(uint256 gasMarker) internal {
        uint256 _rawClaims = (FIXED_GAS_OFFSET + gasMarker) * tx.gasprice;
        (uint256 _atlasSurchargeRate, uint256 _bundlerSurchargeRate) = _surchargeRates();

        // Set any withdraws or deposits
        t_claims = _rawClaims.withSurcharge(_bundlerSurchargeRate);

        // Atlas surcharge is based on the raw claims value.
        t_fees = _rawClaims.getSurcharge(_atlasSurchargeRate);
        t_deposits = msg.value;

        // Explicitly set other transient vars to 0 in case multiple metacalls in single tx.
        t_writeoffs = 0;
        t_withdrawals = 0;
        t_solverSurcharge = 0;
        t_solverLock = 0;
        t_solverTo = address(0);

        // The Lock slot is cleared at the end of the metacall, so no need to zero again here.
    }

    /// @notice Contributes ETH to the contract, increasing the deposits if a non-zero value is sent.
    function contribute() external payable {
        address _activeEnv = _activeEnvironment();
        if (_activeEnv != msg.sender) revert InvalidExecutionEnvironment(_activeEnv);
        _contribute();
    }

    /// @notice Borrows ETH from the contract, transferring the specified amount to the caller if available.
    /// @dev Borrowing is only available until the end of the SolverOperation phase, for solver protection.
    /// @param amount The amount of ETH to borrow.
    function borrow(uint256 amount) external payable {
        if (amount == 0) return;

        // borrow() can only be called by the Execution Environment (by delegatecalling a DAppControl hook), and only
        // during or before the SolverOperation phase.
        (address _activeEnv,, uint8 _currentPhase) = _lock();
        if (_activeEnv != msg.sender) revert InvalidExecutionEnvironment(_activeEnv);
        if (_currentPhase > uint8(ExecutionPhase.SolverOperation)) revert WrongPhase();

        // borrow() will revert if called after solver calls reconcile()
        (, bool _calledBack,) = _solverLockData();
        if (_calledBack) revert WrongPhase();

        if (_borrow(amount)) {
            SafeTransferLib.safeTransferETH(msg.sender, amount);
        } else {
            revert InsufficientAtlETHBalance(address(this).balance, amount);
        }
    }

    /// @notice Calculates the current shortfall currently owed by the winning solver.
    /// @dev The shortfall is calculated `(claims + withdrawals + fees - writeoffs) - deposits`. If this value is less
    /// than zero, shortfall returns 0 as there is no shortfall because the solver is in surplus.
    /// @return uint256 The current shortfall amount, or 0 if there is no shortfall.
    function shortfall() external view returns (uint256) {
        uint256 _currentDeficit = _deficit();
        uint256 _deposits = t_deposits;
        return (_currentDeficit > _deposits) ? (_currentDeficit - _deposits) : 0;
    }

    function _deficit() internal view returns (uint256) {
        // _deficit() is compared against t_deposits which includes:
        // + msg.value deposited
        // + gas cost + A + B (prev solver fault fails)

        // _deficit() is therefore composed of:
        // + withdrawals = msg.value borrowed
        // + claims = gas cost + B (full tx)
        // + fees = A (full tx)
        // - writeoffs = gas cost + A + B (prev bundler fault fails)

        // Such that `deficit() - t_deposits` =
        // + msg.value still owed
        // + gas cost + A + B (full tx)
        // - gas cost + A + B (prev solver fault fails)
        // - gas cost + A + B (prev bundler fault fails)
        // == only what the current solver owes if they win

        return t_withdrawals + t_claims + t_fees - t_writeoffs;
    }

    /// @notice Allows a solver to settle any outstanding ETH owed, either to repay gas used by their solverOp or to
    /// repay any ETH borrowed from Atlas. This debt can be paid either by sending ETH when calling this function
    /// (msg.value) or by approving Atlas to use a certain amount of the solver's bonded AtlETH.
    /// @param maxApprovedGasSpend The maximum amount of the solver's bonded AtlETH that Atlas can deduct to cover the
    /// solver's debt.
    /// @return owed The amount owed, if any, by the solver after reconciliation.
    /// @dev The solver can call this function multiple times until the owed amount is zero.
    /// @dev Note: `reconcile()` must be called by the solver to avoid a `CallbackNotCalled` error in `solverCall()`.
    function reconcile(uint256 maxApprovedGasSpend) external payable returns (uint256 owed) {
        // NOTE: maxApprovedGasSpend is the amount of the solver's atlETH that the solver is allowing
        // to be used to cover what they owe. Assuming they're successful, a value up to this amount
        // will be subtracted from the solver's bonded AtlETH during _settle().

        // NOTE: After reconcile is called for the first time by the solver, neither the claims nor withdrawals values
        // can be increased.

        // NOTE: While anyone can call this function, it can only be called in the SolverOperation phase. Because Atlas
        // calls directly to the solver contract in this phase, the solver should be careful to not call malicious
        // contracts which may call reconcile() on their behalf, with an excessive maxApprovedGasSpend.
        if (_phase() != uint8(ExecutionPhase.SolverOperation)) revert WrongPhase();
        if (msg.sender != t_solverTo) revert InvalidAccess();

        (address _currentSolver, bool _calledBack, bool _fulfilled) = _solverLockData();
        uint256 _bondedBalance = uint256(S_accessData[_currentSolver].bonded);

        // Solver can only approve up to their bonded balance, not more
        if (maxApprovedGasSpend > _bondedBalance) maxApprovedGasSpend = _bondedBalance;

        uint256 _deductions = _deficit();
        uint256 _additions = t_deposits + msg.value;

        // Add msg.value to solver's deposits
        // NOTE: Surplus deposits are credited back to the Solver during settlement.
        // NOTE: This function is called inside the solver try/catch and will be undone if solver fails.
        if (msg.value > 0) t_deposits = _additions;

        // CASE: Callback verified but insufficient balance
        if (_deductions > _additions + maxApprovedGasSpend) {
            if (!_calledBack) {
                // Setting the solverLock here does not make the solver liable for the submitted maxApprovedGasSpend,
                // but it does treat any msg.value as a deposit and allows for either the solver to call back with a
                // higher maxApprovedGasSpend or to have their deficit covered by a contribute during the postSolverOp
                // hook.
                t_solverLock = (uint256(uint160(_currentSolver)) | _SOLVER_CALLED_BACK_MASK);
            }
            return _deductions - _additions;
        }

        // CASE: Callback verified and solver duty fulfilled
        if (!_fulfilled) {
            t_solverLock = (uint256(uint160(_currentSolver)) | _SOLVER_CALLED_BACK_MASK | _SOLVER_FULFILLED_MASK);
        }
        return 0;
    }

    /// @notice Internal function to handle ETH contribution, increasing deposits if a non-zero value is sent.
    function _contribute() internal {
        if (msg.value != 0) t_deposits += msg.value;
    }

    /// @notice Borrows ETH from the contract, transferring the specified amount to the caller if available.
    /// @dev Borrowing should never be allowed after the SolverOperation phase, for solver safety. This is enforced in
    /// the external `borrow` function, and the only other time this internal `_borrow` function is called is in
    /// `_solverOpInner` which happens at the beginning of the SolverOperation phase.
    /// @param amount The amount of ETH to borrow.
    /// @return valid A boolean indicating whether the borrowing operation was successful.
    function _borrow(uint256 amount) internal returns (bool valid) {
        if (amount == 0) return true;
        if (address(this).balance < amount) return false;

        t_withdrawals += amount;

        return true;
    }

    /// @notice Takes AtlETH from the owner's bonded balance and, if necessary, from the owner's unbonding balance to
    /// increase transient solver deposits.
    /// @param owner The address of the owner from whom AtlETH is taken.
    /// @param amount The amount of AtlETH to be taken.
    /// @param gasValueUsed The ETH value of gas used in the SolverOperation.
    /// @param solverWon A boolean indicating whether the solver won the bid.
    /// @return deficit The amount of AtlETH that was not repaid, if any.
    function _assign(
        address owner,
        uint256 amount,
        uint256 gasValueUsed,
        bool solverWon
    )
        internal
        returns (uint256 deficit)
    {
        uint112 _amt = SafeCast.toUint112(amount);

        EscrowAccountAccessData memory _aData = S_accessData[owner];

        if (_amt > _aData.bonded) {
            // The bonded balance does not cover the amount owed. Check if there is enough unbonding balance to
            // make up for the missing difference. If not, there is a deficit. Atlas does not consider drawing from
            // the regular AtlETH balance (not bonded nor unbonding) to cover the remaining deficit because it is
            // not meant to be used within an Atlas transaction, and must remain independent.

            EscrowAccountBalance memory _bData = s_balanceOf[owner];
            uint256 _total = uint256(_bData.unbonding) + uint256(_aData.bonded);

            if (_amt > _total) {
                // The unbonding balance is insufficient to cover the remaining amount owed. There is a deficit. Set
                // both bonded and unbonding balances to 0 and adjust the "amount" variable to reflect the amount
                // that was actually deducted.
                deficit = amount - _total;
                s_balanceOf[owner].unbonding = 0;
                _aData.bonded = 0;

                t_writeoffs += deficit;
                amount -= deficit; // Set amount equal to total to accurately track the changing bondedTotalSupply
            } else {
                // The unbonding balance is sufficient to cover the remaining amount owed. Draw everything from the
                // bonded balance, and adjust the unbonding balance accordingly.
                s_balanceOf[owner].unbonding = SafeCast.toUint112(_total - _amt);
                _aData.bonded = 0;
            }
        } else {
            // The bonded balance is sufficient to cover the amount owed.
            _aData.bonded -= _amt;
        }

        // Update analytics (auctionWins, auctionFails, totalGasValueUsed) and lastAccessedBlock
        _updateAnalytics(_aData, solverWon && deficit == 0, gasValueUsed);
        _aData.lastAccessedBlock = uint32(block.number);

        // Persist changes in the _aData memory struct back to storage
        S_accessData[owner] = _aData;

        S_bondedTotalSupply -= amount;
        t_deposits += amount;
    }

    /// @notice Increases the owner's bonded balance by the specified amount.
    /// @param owner The address of the owner whose bonded balance will be increased.
    /// @param amount The amount by which to increase the owner's bonded balance.
    /// @param gasValueUsed The ETH value of gas used in the SolverOperation.
    function _credit(address owner, uint256 amount, uint256 gasValueUsed) internal {
        EscrowAccountAccessData memory _aData = S_accessData[owner];

        _aData.lastAccessedBlock = uint32(block.number);
        _aData.bonded += SafeCast.toUint112(amount);

        S_bondedTotalSupply += amount;

        // Update analytics (auctionWins, auctionFails, totalGasValueUsed)
        _updateAnalytics(_aData, true, gasValueUsed);

        // Persist changes in the _aData memory struct back to storage
        S_accessData[owner] = _aData;
        t_withdrawals += amount;
    }

    /// @notice Accounts for the gas cost of a failed SolverOperation, either by increasing writeoffs (if the bundler is
    /// blamed for the failure) or by assigning the gas cost to the solver's bonded AtlETH balance (if the solver is
    /// blamed for the failure).
    /// @param solverOp The current SolverOperation for which to account.
    /// @param gasWaterMark The `gasleft()` watermark taken at the start of executing the SolverOperation.
    /// @param result The result bitmap of the SolverOperation execution.
    /// @param includeCalldata Whether to include calldata cost in the gas calculation.
    function _handleSolverAccounting(
        SolverOperation calldata solverOp,
        uint256 gasWaterMark,
        uint256 result,
        bool includeCalldata
    )
        internal
    {
        uint256 _gasUsed = (gasWaterMark + _SOLVER_BASE_GAS_USED - gasleft()) * tx.gasprice;
        (uint256 _atlasSurchargeRate, uint256 _bundlerSurchargeRate) = _surchargeRates();

        if (includeCalldata) {
            _gasUsed += _getCalldataCost(solverOp.data.length);
        }

        // Calculate what the solver owes
        // NOTE: This will cause an error if you are simulating with a gasPrice of 0
        if (result.bundlersFault()) {
            // CASE: Solver is not responsible for the failure of their operation, so we blame the bundler
            // and reduce the total amount refunded to the bundler
            t_writeoffs += _gasUsed.withSurcharges(_atlasSurchargeRate, _bundlerSurchargeRate);
        } else {
            // CASE: Solver failed, so we calculate what they owe.
            uint256 _gasUsedWithSurcharges = _gasUsed.withSurcharges(_atlasSurchargeRate, _bundlerSurchargeRate);
            uint256 _surchargesOnly = _gasUsedWithSurcharges - _gasUsed;

            // In `_assign()`, the failing solver's bonded AtlETH balance is reduced by `_gasUsedWithSurcharges`. Any
            // deficit from that operation is added to `writeoffs` and returned as `_assignDeficit` below. The portion
            // that can be covered by the solver's AtlETH is added to `deposits`, to account that it has been paid.
            uint256 _assignDeficit = _assign(solverOp.from, _gasUsedWithSurcharges, _gasUsedWithSurcharges, false);

            // We track the surcharges (in excess of deficit - so the actual AtlETH that can be collected) separately,
            // so that in the event of no successful solvers, any `_assign()`ed surcharges can be attributed to an
            // increase in Atlas' cumulative surcharge.
            if (_surchargesOnly > _assignDeficit) {
                t_solverSurcharge += (_surchargesOnly - _assignDeficit);
            }
        }
    }

    function _writeOffBidFindGasCost(uint256 gasUsed) internal {
        (uint256 _atlasSurchargeRate, uint256 _bundlerSurchargeRate) = _surchargeRates();
        t_writeoffs += gasUsed.withSurcharges(_atlasSurchargeRate, _bundlerSurchargeRate);
    }

    /// @param ctx Context struct containing relevant context information for the Atlas auction.
    /// @param solverGasLimit The maximum gas limit for a solver, as set in the DAppConfig
    /// @return adjustedWithdrawals Withdrawals of the current metacall, adjusted by adding the Atlas gas surcharge.
    /// @return adjustedClaims Claims of the current metacall, adjusted by subtracting the unused gas scaled to include
    /// bundler surcharge.
    /// @return adjustedWriteoffs Writeoffs of the current metacall, adjusted by adding the bundler gas overage penalty
    /// if applicable.
    /// @return netAtlasGasSurcharge The net gas surcharge of the metacall, taken by Atlas.
    /// @dev This function is called internally to adjust the accounting for fees based on the gas usage.
    /// Note: The behavior of this function depends on whether `_bidFindingIteration()` or `_bidKnownIteration()` is
    /// used, as they both use a different order of execution.
    function _adjustAccountingForFees(
        Context memory ctx,
        uint256 solverGasLimit
    )
        internal
        returns (
            uint256 adjustedWithdrawals,
            uint256 adjustedClaims,
            uint256 adjustedWriteoffs,
            uint256 netAtlasGasSurcharge
        )
    {
        uint256 _surcharge = S_cumulativeSurcharge;

        adjustedWithdrawals = t_withdrawals;
        adjustedClaims = t_claims;
        adjustedWriteoffs = t_writeoffs;
        uint256 _fees = t_fees;
        (uint256 _atlasSurchargeRate, uint256 _bundlerSurchargeRate) = _surchargeRates();

        uint256 _gasLeft = gasleft(); // Hold this constant for the calculations

        // Estimate the unspent, remaining gas that the Solver will not be liable for.
        uint256 _gasRemainder = _gasLeft * tx.gasprice;

        adjustedClaims -= _gasRemainder.withSurcharge(_bundlerSurchargeRate);

        if (ctx.solverSuccessful) {
            // If a solver was successful, calc the full Atlas gas surcharge on the gas cost of the entire metacall, and
            // add it to withdrawals so that the cost is assigned to winning solver by the end of _settle(). This will
            // be offset by any gas surcharge paid by failed solvers, which would have been added to deposits or
            // writeoffs in _handleSolverAccounting(). As such, the winning solver does not pay for surcharge on the gas
            // used by other solvers.
            netAtlasGasSurcharge = _fees - _gasRemainder.getSurcharge(_atlasSurchargeRate);
            adjustedWithdrawals += netAtlasGasSurcharge;
            S_cumulativeSurcharge = _surcharge + netAtlasGasSurcharge;
        } else {
            // If no successful solvers, only collect partial surcharges from solver's fault failures (if any)
            uint256 _solverSurcharge = t_solverSurcharge;
            if (_solverSurcharge > 0) {
                netAtlasGasSurcharge = _solverSurcharge.getPortionFromTotalSurcharge({
                    targetSurchargeRate: _atlasSurchargeRate,
                    totalSurchargeRate: _atlasSurchargeRate + _bundlerSurchargeRate
                });

                // When no winning solvers, bundler max refund is 80% of metacall gas cost. The remaining 20% can be
                // collected through storage refunds. Any excess bundler surcharge is instead taken as Atlas surcharge.
                uint256 _bundlerSurcharge = _solverSurcharge - netAtlasGasSurcharge;
                uint256 _maxBundlerRefund = adjustedClaims.withoutSurcharge(_bundlerSurchargeRate).maxBundlerRefund();
                if (_bundlerSurcharge > _maxBundlerRefund) {
                    netAtlasGasSurcharge += _bundlerSurcharge - _maxBundlerRefund;
                }

                adjustedWithdrawals += netAtlasGasSurcharge;
                S_cumulativeSurcharge = _surcharge + netAtlasGasSurcharge;
            }
            return (adjustedWithdrawals, adjustedClaims, adjustedWriteoffs, netAtlasGasSurcharge);
        }

        // Calculate whether or not the bundler used an excessive amount of gas and, if so, reduce their
        // gas rebate. By reducing the claims, solvers end up paying less in total.
        if (ctx.solverCount > 0) {
            // Calculate the unadjusted bundler gas surcharge
            uint256 _grossBundlerGasSurcharge = adjustedClaims.withoutSurcharge(_bundlerSurchargeRate);

            // Calculate an estimate for how much gas should be remaining
            // NOTE: There is a free buffer of one SolverOperation because solverIndex starts at 0.
            uint256 _upperGasRemainingEstimate =
                (solverGasLimit * (ctx.solverCount - ctx.solverIndex)) + _BUNDLER_GAS_PENALTY_BUFFER;

            // Increase the writeoffs value if the bundler set too high of a gas parameter and forced solvers to
            // maintain higher escrow balances.
            if (_gasLeft > _upperGasRemainingEstimate) {
                // Penalize the bundler's gas
                uint256 _bundlerGasOveragePenalty =
                    _grossBundlerGasSurcharge - (_grossBundlerGasSurcharge * _upperGasRemainingEstimate / _gasLeft);
                adjustedWriteoffs += _bundlerGasOveragePenalty;
            }
        }
    }

    /// @notice Settle makes the final adjustments to accounting variables based on gas used in the metacall. AtlETH is
    /// either taken (via _assign) or given (via _credit) to the winning solver, the bundler is sent the appropriate
    /// refund for gas spent, and Atlas' gas surcharge is updated.
    /// @param ctx Context struct containing relevant context information for the Atlas auction.
    /// @param solverGasLimit The dApp's maximum gas limit for a solver, as set in the DAppConfig.
    /// @param gasRefundBeneficiary The address to receive the gas refund.
    /// @return claimsPaidToBundler The amount of ETH paid to the bundler in this function.
    /// @return netAtlasGasSurcharge The net gas surcharge of the metacall, taken by Atlas.
    function _settle(
        Context memory ctx,
        uint256 solverGasLimit,
        address gasRefundBeneficiary
    )
        internal
        returns (uint256 claimsPaidToBundler, uint256 netAtlasGasSurcharge)
    {
        // NOTE: If there is no winning solver but the dApp config allows unfulfilled 'successes', the bundler
        // is treated as the solver.

        // If a solver won, their address is still in the _solverLock
        (address _winningSolver,,) = _solverLockData();

        if (gasRefundBeneficiary == address(0)) gasRefundBeneficiary = ctx.bundler;

        // Load what we can from storage so that it shows up in the gasleft() calc

        uint256 _claims;
        uint256 _writeoffs;
        uint256 _withdrawals;
        uint256 _deposits = t_deposits; // load here, not used in adjustment function below

        (_withdrawals, _claims, _writeoffs, netAtlasGasSurcharge) = _adjustAccountingForFees(ctx, solverGasLimit);

        uint256 _amountSolverPays;
        uint256 _amountSolverReceives;
        uint256 _adjustedClaims = _claims - _writeoffs;

        // Calculate the balances that should be debited or credited to the solver and the bundler
        if (_deposits < _withdrawals) {
            _amountSolverPays = _withdrawals - _deposits;
        } else {
            _amountSolverReceives = _deposits - _withdrawals;
        }

        // Only force solver to pay gas claims if they aren't also the bundler
        // NOTE: If the auction isn't won, _winningSolver will be address(0).
        if (ctx.solverSuccessful && _winningSolver != ctx.bundler) {
            _amountSolverPays += _adjustedClaims;
            claimsPaidToBundler = _adjustedClaims;
        } else if (_winningSolver == ctx.bundler) {
            claimsPaidToBundler = 0;
        } else {
            // this else block is only executed if there is no successful solver
            claimsPaidToBundler = 0;
            _winningSolver = gasRefundBeneficiary;
        }

        if (_amountSolverPays > _amountSolverReceives) {
            if (!ctx.solverSuccessful) {
                revert InsufficientTotalBalance(_amountSolverPays - _amountSolverReceives);
            }

            uint256 _currentDeficit =
                _assign(_winningSolver, _amountSolverPays - _amountSolverReceives, _adjustedClaims, true);
            if (_currentDeficit > claimsPaidToBundler) {
                revert InsufficientTotalBalance(_currentDeficit - claimsPaidToBundler);
            }
            claimsPaidToBundler -= _currentDeficit;
        } else {
            _credit(_winningSolver, _amountSolverReceives - _amountSolverPays, _adjustedClaims);
        }

        // Set lock to FullyLocked to prevent any reentrancy possibility
        _setLockPhase(uint8(ExecutionPhase.FullyLocked));

        if (claimsPaidToBundler != 0) SafeTransferLib.safeTransferETH(gasRefundBeneficiary, claimsPaidToBundler);

        return (claimsPaidToBundler, netAtlasGasSurcharge);
    }

    /// @notice Updates auctionWins, auctionFails, and totalGasUsed values of a solver's EscrowAccountAccessData.
    /// @dev This function is only ever called in the context of bidFind = false so no risk of doublecounting changes.
    /// @param aData The Solver's EscrowAccountAccessData struct to update.
    /// @param auctionWon A boolean indicating whether the solver's solverOp won the auction.
    /// @param gasValueUsed The ETH value of gas used by the solverOp. Should be calculated as gasUsed * tx.gasprice.
    function _updateAnalytics(
        EscrowAccountAccessData memory aData,
        bool auctionWon,
        uint256 gasValueUsed
    )
        internal
        pure
    {
        if (auctionWon) {
            unchecked {
                ++aData.auctionWins;
            }
        } else {
            unchecked {
                ++aData.auctionFails;
            }
        }

        // Track total ETH value of gas spent by solver in metacalls. Measured in gwei (1e9 digits truncated).
        aData.totalGasValueUsed += SafeCast.toUint64(gasValueUsed / _GAS_VALUE_DECIMALS_TO_DROP);
    }

    /// @notice Calculates the gas cost of the calldata used to execute a SolverOperation.
    /// @param calldataLength The length of the `data` field in the SolverOperation.
    /// @return calldataCost The gas cost of the calldata used to execute the SolverOperation.
    function _getCalldataCost(uint256 calldataLength) internal view returns (uint256 calldataCost) {
        if (L2_GAS_CALCULATOR == address(0)) {
            // Default to using mainnet gas calculations
            // _SOLVER_OP_BASE_CALLDATA = SolverOperation calldata length excluding solverOp.data
            calldataCost = (calldataLength + _SOLVER_OP_BASE_CALLDATA) * _CALLDATA_LENGTH_PREMIUM_HALVED * tx.gasprice;
        } else {
            calldataCost =
                IL2GasCalculator(L2_GAS_CALCULATOR).getCalldataCost(calldataLength + _SOLVER_OP_BASE_CALLDATA);
        }
    }

    /// @notice Checks if the current balance is reconciled.
    /// @dev Compares the deposits with the sum of claims, withdrawals, fees, and write-offs to ensure the balance is
    /// correct.
    /// @return True if the balance is reconciled, false otherwise.
    function _isBalanceReconciled() internal view returns (bool) {
        return t_deposits >= _deficit();
    }
}

File 33 of 35 : SafetyLocks.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import { Storage } from "./Storage.sol";
import { CallBits } from "../libraries/CallBits.sol";
import "../types/SolverOperation.sol";
import "../types/UserOperation.sol";
import "../types/ConfigTypes.sol";
import "../types/EscrowTypes.sol";
import "../types/LockTypes.sol";

/// @title SafetyLocks
/// @author FastLane Labs
/// @notice SafetyLocks manages the locking and unlocking of the Atlas environment during the execution of a metacall
/// transaction.
abstract contract SafetyLocks is Storage {
    using CallBits for uint32;

    constructor(
        uint256 escrowDuration,
        uint256 atlasSurchargeRate,
        uint256 bundlerSurchargeRate,
        address verification,
        address simulator,
        address initialSurchargeRecipient,
        address l2GasCalculator
    )
        Storage(
            escrowDuration,
            atlasSurchargeRate,
            bundlerSurchargeRate,
            verification,
            simulator,
            initialSurchargeRecipient,
            l2GasCalculator
        )
    { }

    /// @notice Sets the Atlas lock to the specified execution environment.
    /// @param dConfig The DAppConfig of the current DAppControl contract.
    /// @param executionEnvironment The address of the execution environment to set the lock to.
    function _setEnvironmentLock(DAppConfig memory dConfig, address executionEnvironment) internal {
        if (!_isUnlocked()) revert AlreadyInitialized();

        // Initialize the Lock
        _setLock({
            activeEnvironment: executionEnvironment,
            callConfig: dConfig.callConfig,
            phase: uint8(ExecutionPhase.PreOps)
        });
    }

    modifier withLockPhase(ExecutionPhase executionPhase) {
        _setLockPhase(uint8(executionPhase));
        _;
    }

    /// @notice Builds an Context struct with the specified parameters, called at the start of
    /// `_preOpsUserExecutionIteration`.
    /// @param executionEnvironment The address of the current Execution Environment.
    /// @param userOpHash The UserOperation hash.
    /// @param bundler The address of the bundler.
    /// @param solverOpCount The count of SolverOperations.
    /// @param isSimulation Boolean indicating whether the call is a simulation or not.
    /// @return An Context struct initialized with the provided parameters.
    function _buildContext(
        address executionEnvironment,
        bytes32 userOpHash,
        address bundler,
        uint8 solverOpCount,
        bool isSimulation
    )
        internal
        pure
        returns (Context memory)
    {
        return Context({
            executionEnvironment: executionEnvironment,
            userOpHash: userOpHash,
            bundler: bundler,
            solverSuccessful: false,
            paymentsSuccessful: false,
            solverIndex: 0,
            solverCount: solverOpCount,
            phase: uint8(ExecutionPhase.PreOps),
            solverOutcome: 0,
            bidFind: false,
            isSimulation: isSimulation,
            callDepth: 0
        });
    }
}

File 34 of 35 : Storage.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "../types/EscrowTypes.sol";
import "../types/LockTypes.sol";
import "../libraries/AccountingMath.sol";

import { AtlasEvents } from "../types/AtlasEvents.sol";
import { AtlasErrors } from "../types/AtlasErrors.sol";
import { AtlasConstants } from "../types/AtlasConstants.sol";
import { IAtlasVerification } from "../interfaces/IAtlasVerification.sol";

/// @title Storage
/// @author FastLane Labs
/// @notice Storage manages all storage variables and constants for the Atlas smart contract.
contract Storage is AtlasEvents, AtlasErrors, AtlasConstants {
    IAtlasVerification public immutable VERIFICATION;
    address public immutable SIMULATOR;
    address public immutable L2_GAS_CALCULATOR;
    uint256 public immutable ESCROW_DURATION;

    // AtlETH public constants
    // These constants double as interface functions for the ERC20 standard, hence the lowercase naming convention.
    string public constant name = "Atlas ETH";
    string public constant symbol = "atlETH";
    uint8 public constant decimals = 18;

    // Gas Accounting public constants
    uint256 public constant SCALE = AccountingMath._SCALE;
    uint256 public constant FIXED_GAS_OFFSET = AccountingMath._FIXED_GAS_OFFSET;

    // Transient storage slots
    uint256 internal transient t_lock; // contains activeAddress, callConfig, and phase
    uint256 internal transient t_solverLock; 
    address internal transient t_solverTo; // current solverOp.solver contract address

    // solverSurcharge = total surcharge collected from failed solverOps due to solver fault.
    uint256 internal transient t_solverSurcharge;
    uint256 internal transient t_claims;
    uint256 internal transient t_fees;
    uint256 internal transient t_writeoffs;
    uint256 internal transient t_withdrawals;
    uint256 internal transient t_deposits;

    // AtlETH storage
    uint256 internal S_totalSupply;
    uint256 internal S_bondedTotalSupply;

    // Surcharge-related storage
    uint256 internal S_surchargeRates; // left 128 bits: Atlas rate, right 128 bits: Bundler rate
    uint256 internal S_cumulativeSurcharge; // Cumulative gas surcharges collected
    address internal S_surchargeRecipient; // Fastlane surcharge recipient
    address internal S_pendingSurchargeRecipient; // For 2-step transfer process

    mapping(address => EscrowAccountBalance) internal s_balanceOf; // public balanceOf will return a uint256
    mapping(address => EscrowAccountAccessData) internal S_accessData;
    mapping(bytes32 => bool) internal S_solverOpHashes; // NOTE: Only used for when allowTrustedOpHash is enabled
    
    constructor(
        uint256 escrowDuration,
        uint256 atlasSurchargeRate,
        uint256 bundlerSurchargeRate,
        address verification,
        address simulator,
        address initialSurchargeRecipient,
        address l2GasCalculator
    )
        payable
    {
        VERIFICATION = IAtlasVerification(verification);
        SIMULATOR = simulator;
        L2_GAS_CALCULATOR = l2GasCalculator;
        ESCROW_DURATION = escrowDuration;

        // Check Atlas and Bundler gas surcharges fit in 128 bits each
        if(atlasSurchargeRate > type(uint128).max || bundlerSurchargeRate > type(uint128).max) {
            revert SurchargeRateTooHigh();
        }

        S_surchargeRates = atlasSurchargeRate << 128 | bundlerSurchargeRate;
        S_cumulativeSurcharge = msg.value;
        S_surchargeRecipient = initialSurchargeRecipient;

        emit SurchargeRecipientTransferred(initialSurchargeRecipient);
    }

    // ---------------------------------------------------- //
    //                     Storage Setters                  //
    // ---------------------------------------------------- //

    function setSurchargeRates(uint256 newAtlasRate, uint256 newBundlerRate) external {
        _onlySurchargeRecipient();

        // Check Atlas and Bundler gas surcharges fit in 128 bits each
        if(newAtlasRate > type(uint128).max || newBundlerRate > type(uint128).max) {
            revert SurchargeRateTooHigh();
        }

        S_surchargeRates = newAtlasRate << 128 | newBundlerRate;
    }

    function _onlySurchargeRecipient() internal view {
        if (msg.sender != S_surchargeRecipient) {
            revert InvalidAccess();
        }
    }

    // ---------------------------------------------------- //
    //                     Storage Getters                  //
    // ---------------------------------------------------- //
    function totalSupply() external view returns (uint256) {
        return S_totalSupply;
    }

    function bondedTotalSupply() external view returns (uint256) {
        return S_bondedTotalSupply;
    }

    function accessData(address account)
        external
        view
        returns (
            uint112 bonded,
            uint32 lastAccessedBlock,
            uint24 auctionWins,
            uint24 auctionFails,
            uint64 totalGasValueUsed
        )
    {
        EscrowAccountAccessData memory _aData = S_accessData[account];

        bonded = _aData.bonded;
        lastAccessedBlock = _aData.lastAccessedBlock;
        auctionWins = _aData.auctionWins;
        auctionFails = _aData.auctionFails;
        totalGasValueUsed = _aData.totalGasValueUsed;
    }

    function solverOpHashes(bytes32 opHash) external view returns (bool) {
        return S_solverOpHashes[opHash];
    }

    function cumulativeSurcharge() external view returns (uint256) {
        return S_cumulativeSurcharge;
    }

    function surchargeRecipient() external view returns (address) {
        return S_surchargeRecipient;
    }

    function pendingSurchargeRecipient() external view returns (address) {
        return S_pendingSurchargeRecipient;
    }

    function atlasSurchargeRate() external view returns (uint256) {
        // Includes only the left 128 bits to isolate the Atlas rate
        return S_surchargeRates >> 128;
    }

    function bundlerSurchargeRate() external view returns (uint256) {
        // Includes only the right 128 bits to isolate the bundler rate
        return S_surchargeRates & ((1 << 128) - 1);
    }

    // ---------------------------------------------------- //
    //               Storage Internal Getters               //
    // ---------------------------------------------------- //

    function _surchargeRates() internal view returns (uint256 atlasRate, uint256 bundlerRate) {
        uint256 _bothRates = S_surchargeRates;
        atlasRate = _bothRates >> 128;
        bundlerRate = _bothRates & ((1 << 128) - 1);
    }

    // ---------------------------------------------------- //
    //              Transient External Getters              //
    // ---------------------------------------------------- //

    function lock() external view returns (address activeEnvironment, uint32 callConfig, uint8 phase) {
        return _lock();
    }

    /// @notice Returns the current lock state of Atlas.
    /// @return Boolean indicating whether Atlas is in a locked state or not.
    function isUnlocked() external view returns (bool) {
        return _isUnlocked();
    }

    /// @notice Returns information about the current state of the solver lock.
    /// @return currentSolver Address of the current solver.
    /// @return calledBack Boolean indicating whether the solver has called back via `reconcile`.
    /// @return fulfilled Boolean indicating whether the solver's outstanding debt has been repaid via `reconcile`.
    function solverLockData() external view returns (address currentSolver, bool calledBack, bool fulfilled) {
        return _solverLockData();
    }

    // ---------------------------------------------------- //
    //              Transient Internal Getters              //
    // ---------------------------------------------------- //

    function _lock() internal view returns (address activeEnvironment, uint32 callConfig, uint8 phase) {
        uint256 _lockData = t_lock;
        activeEnvironment = address(uint160(_lockData >> 40));
        callConfig = uint32(_lockData >> 8);
        phase = uint8(_lockData);
    }

    function _activeEnvironment() internal view returns (address) {
        // right shift 40 bits to remove the callConfig and phase, only activeEnvironment remains
        return address(uint160(t_lock >> 40));
    }

    function _activeCallConfig() internal view returns (uint32) {
        // right shift 8 bits to remove the phase, cast to uint32 to remove the activeEnvironment
        return uint32(t_lock >> 8);
    }

    function _phase() internal view returns (uint8) {
        // right-most 8 bits of Lock are the phase
        return uint8(t_lock);
    }

    /// @notice Returns information about the current state of the solver lock.
    /// @return currentSolver Address of the current solver.
    /// @return calledBack Boolean indicating whether the solver has called back via `reconcile`.
    /// @return fulfilled Boolean indicating whether the solver's outstanding debt has been repaid via `reconcile`.
    function _solverLockData() internal view returns (address currentSolver, bool calledBack, bool fulfilled) {
        uint256 _solverLock = t_solverLock;
        currentSolver = address(uint160(_solverLock));
        calledBack = _solverLock & _SOLVER_CALLED_BACK_MASK != 0;
        fulfilled = _solverLock & _SOLVER_FULFILLED_MASK != 0;
    }

    function _isUnlocked() internal view returns (bool) {
        return t_lock == _UNLOCKED;
    }

    // ---------------------------------------------------- //
    //                   Transient Setters                  //
    // ---------------------------------------------------- //

    function _setLock(address activeEnvironment, uint32 callConfig, uint8 phase) internal {
        // Pack the lock slot from the right:
        // [   56 bits   ][     160 bits      ][  32 bits   ][ 8 bits ]
        // [ unused bits ][ activeEnvironment ][ callConfig ][ phase  ]
        t_lock = uint256(uint160(activeEnvironment)) << 40 | uint256(callConfig) << 8 | uint256(phase);
    }

    function _releaseLock() internal {
        t_lock = _UNLOCKED;
    }

    // Sets the Lock phase without changing the activeEnvironment or callConfig.
    function _setLockPhase(uint8 newPhase) internal {
        t_lock = (t_lock & _LOCK_PHASE_MASK) | uint256(newPhase);
    }
}

File 35 of 35 : AtlasConstants.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "./ValidCalls.sol";

// NOTE: Internal constants that are defined but not used in the logic of a smart contract, will NOT be included in the
// bytecode of the smart contract when compiled. However, public constants will be included in every inheriting contract
// as they are part of the ABI. As such, only internal constants are defined in this shared contract.

contract AtlasConstants {
    // ------------------------------------------------------- //
    //                      ATLAS CONSTANTS                    //
    // ------------------------------------------------------- //

    // Atlas constants
    uint256 internal constant _GAS_VALUE_DECIMALS_TO_DROP = 1e9; // measured in gwei
    uint256 internal constant _UNLOCKED = 0;

    // Atlas constants used in `_bidFindingIteration()`
    uint256 internal constant _BITS_FOR_INDEX = 16;
    uint256 internal constant _FIRST_16_BITS_TRUE_MASK = uint256(0xFFFF);

    // Escrow constants
    uint256 internal constant _VALIDATION_GAS_LIMIT = 500_000;
    uint256 internal constant _FASTLANE_GAS_BUFFER = 125_000; // integer amount
    uint256 internal constant _GRACEFUL_RETURN_GAS_OFFSET = 40_000;

    // Gas Accounting constants
    uint256 internal constant _CALLDATA_LENGTH_PREMIUM_HALVED = 8; // Half of the upper gas cost per byte of calldata
        // (16 gas). Multiplied by msg.data.length. Equivalent to `msg.data.length / 2 * 16` because 2 hex chars per
        // byte.
    uint256 internal constant _BASE_TRANSACTION_GAS_USED = 21_000;
    uint256 internal constant _SOLVER_OP_BASE_CALLDATA = 608; // SolverOperation calldata length excluding solverOp.data
    uint256 internal constant _SOLVER_BASE_GAS_USED = 5000; // Base gas charged to solver in `_handleSolverAccounting()`
    uint256 internal constant _BUNDLER_GAS_PENALTY_BUFFER = 500_000;

    // First 160 bits of _solverLock are the address of the current solver.
    // The 161st bit represents whether the solver has called back via `reconcile`.
    // The 162nd bit represents whether the solver's outstanding debt has been repaid via `reconcile`.
    uint256 internal constant _SOLVER_CALLED_BACK_MASK = 1 << 161;
    uint256 internal constant _SOLVER_FULFILLED_MASK = 1 << 162;

    // Used to set Lock phase without changing the activeEnvironment or callConfig.
    uint256 internal constant _LOCK_PHASE_MASK =
        uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00);

    // ValidCalls error threshold before which the metacall reverts, and after which it returns gracefully to store
    // nonces as used.
    uint8 internal constant _GRACEFUL_RETURN_THRESHOLD = uint8(ValidCallsResult.InvertBidValueCannotBeExPostBids) + 1;

    // ------------------------------------------------------- //
    //               ATLAS VERIFICATION CONSTANTS              //
    // ------------------------------------------------------- //

    uint8 internal constant _MAX_SOLVERS = type(uint8).max - 1;
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "forge-std/=lib/forge-std/src/",
    "hardhat/=node_modules/hardhat/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solady/=lib/solady/src/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 50
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"uint256","name":"escrowDuration","type":"uint256"},{"internalType":"uint256","name":"atlasSurchargeRate","type":"uint256"},{"internalType":"uint256","name":"bundlerSurchargeRate","type":"uint256"},{"internalType":"address","name":"verification","type":"address"},{"internalType":"address","name":"simulator","type":"address"},{"internalType":"address","name":"initialSurchargeRecipient","type":"address"},{"internalType":"address","name":"l2GasCalculator","type":"address"},{"internalType":"address","name":"factoryLib","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AllocateValueDelegatecallFail","type":"error"},{"inputs":[],"name":"AllocateValueFail","type":"error"},{"inputs":[],"name":"AllocateValueSimFail","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AlteredControl","type":"error"},{"inputs":[],"name":"AtlasLockActive","type":"error"},{"inputs":[],"name":"BalanceNotReconciled","type":"error"},{"inputs":[{"internalType":"uint256","name":"bidAmount","type":"uint256"}],"name":"BidFindSuccessful","type":"error"},{"inputs":[],"name":"BidNotPaid","type":"error"},{"inputs":[],"name":"BothPreOpsAndUserReturnDataCannotBeTracked","type":"error"},{"inputs":[],"name":"BothUserAndDAppNoncesCannotBeSequential","type":"error"},{"inputs":[],"name":"CallbackNotCalled","type":"error"},{"inputs":[],"name":"DAppNotEnabled","type":"error"},{"inputs":[],"name":"DoubleReconcile","type":"error"},{"inputs":[],"name":"EnvironmentMismatch","type":"error"},{"inputs":[],"name":"EscrowLockActive","type":"error"},{"inputs":[],"name":"ExecutionEnvironmentBalanceTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientAtlETHBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"InsufficientBalanceForDeduction","type":"error"},{"inputs":[],"name":"InsufficientEscrow","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InsufficientLocalFunds","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"msgValue","type":"uint256"},{"internalType":"uint256","name":"holds","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientSolverBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"shortfall","type":"uint256"}],"name":"InsufficientTotalBalance","type":"error"},{"inputs":[],"name":"InvalidAccess","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidCodeHash","type":"error"},{"inputs":[],"name":"InvalidControl","type":"error"},{"inputs":[],"name":"InvalidDAppControl","type":"error"},{"inputs":[],"name":"InvalidEntry","type":"error"},{"inputs":[],"name":"InvalidEntryFunction","type":"error"},{"inputs":[],"name":"InvalidEnvironment","type":"error"},{"inputs":[],"name":"InvalidEscrowDuration","type":"error"},{"inputs":[{"internalType":"address","name":"correctEnvironment","type":"address"}],"name":"InvalidExecutionEnvironment","type":"error"},{"inputs":[],"name":"InvalidLockState","type":"error"},{"inputs":[],"name":"InvalidSignatory","type":"error"},{"inputs":[],"name":"InvalidSolver","type":"error"},{"inputs":[{"internalType":"address","name":"solverFrom","type":"address"}],"name":"InvalidSolverFrom","type":"error"},{"inputs":[],"name":"InvalidTo","type":"error"},{"inputs":[],"name":"InvalidUser","type":"error"},{"inputs":[],"name":"InvertBidValueCannotBeExPostBids","type":"error"},{"inputs":[],"name":"InvertedBidExceedsCeiling","type":"error"},{"inputs":[{"internalType":"uint8","name":"id","type":"uint8"}],"name":"LedgerBalancing","type":"error"},{"inputs":[{"internalType":"uint8","name":"id","type":"uint8"}],"name":"LedgerFinalized","type":"error"},{"inputs":[{"internalType":"uint8","name":"id","type":"uint8"}],"name":"MissingFunds","type":"error"},{"inputs":[],"name":"MustBeDelegatecalled","type":"error"},{"inputs":[],"name":"NoAuctionWinner","type":"error"},{"inputs":[],"name":"NoDelegatecall","type":"error"},{"inputs":[],"name":"NoUnfilledRequests","type":"error"},{"inputs":[],"name":"NoUnusedNonceInBitmap","type":"error"},{"inputs":[],"name":"NotEnvironmentOwner","type":"error"},{"inputs":[],"name":"NotImplemented","type":"error"},{"inputs":[],"name":"NotInitialized","type":"error"},{"inputs":[],"name":"OnlyAtlas","type":"error"},{"inputs":[],"name":"OnlyGovernance","type":"error"},{"inputs":[],"name":"PostOpsDelegatecallFail","type":"error"},{"inputs":[],"name":"PostOpsDelegatecallReturnedFalse","type":"error"},{"inputs":[],"name":"PostOpsFail","type":"error"},{"inputs":[],"name":"PostOpsSimFail","type":"error"},{"inputs":[],"name":"PostSolverFailed","type":"error"},{"inputs":[],"name":"PreOpsDelegatecallFail","type":"error"},{"inputs":[],"name":"PreOpsFail","type":"error"},{"inputs":[],"name":"PreOpsSimFail","type":"error"},{"inputs":[],"name":"PreSolverFailed","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"SignatoryActive","type":"error"},{"inputs":[],"name":"SimulationPassed","type":"error"},{"inputs":[],"name":"SimulatorBalanceTooLow","type":"error"},{"inputs":[],"name":"SolverMustReconcile","type":"error"},{"inputs":[],"name":"SolverOpReverted","type":"error"},{"inputs":[{"internalType":"uint256","name":"solverOutcomeResult","type":"uint256"}],"name":"SolverSimFail","type":"error"},{"inputs":[],"name":"SurchargeRateTooHigh","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnbalancedAccounting","type":"error"},{"inputs":[],"name":"UncoveredResult","type":"error"},{"inputs":[],"name":"UnexpectedNonRevert","type":"error"},{"inputs":[],"name":"Unreachable","type":"error"},{"inputs":[],"name":"UserNotFulfilled","type":"error"},{"inputs":[],"name":"UserOpFail","type":"error"},{"inputs":[],"name":"UserOpSimFail","type":"error"},{"inputs":[],"name":"UserOpValueExceedsBalance","type":"error"},{"inputs":[],"name":"UserSimulationFailed","type":"error"},{"inputs":[],"name":"UserSimulationSucceeded","type":"error"},{"inputs":[],"name":"UserUnexpectedSuccess","type":"error"},{"inputs":[],"name":"UserWrapperCallFail","type":"error"},{"inputs":[],"name":"UserWrapperDelegatecallFail","type":"error"},{"inputs":[{"internalType":"enum ValidCallsResult","name":"","type":"uint8"}],"name":"ValidCalls","type":"error"},{"inputs":[{"internalType":"enum ValidCallsResult","name":"","type":"uint8"}],"name":"VerificationSimFail","type":"error"},{"inputs":[],"name":"WrongDepth","type":"error"},{"inputs":[],"name":"WrongPhase","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Bond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"control","type":"address"},{"indexed":true,"internalType":"address","name":"governance","type":"address"},{"indexed":false,"internalType":"uint32","name":"callConfig","type":"uint32"}],"name":"DAppDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"control","type":"address"},{"indexed":true,"internalType":"address","name":"oldGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"},{"indexed":false,"internalType":"uint32","name":"callConfig","type":"uint32"}],"name":"DAppGovernanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"executionEnvironment","type":"address"}],"name":"ExecutionEnvironmentCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bundler","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bool","name":"solverSuccessful","type":"bool"},{"indexed":false,"internalType":"bool","name":"disbursementSuccessful","type":"bool"},{"indexed":false,"internalType":"uint256","name":"ethPaidToBundler","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"netGasSurcharge","type":"uint256"}],"name":"MetacallResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"control","type":"address"},{"indexed":true,"internalType":"address","name":"governance","type":"address"},{"indexed":true,"internalType":"address","name":"signatory","type":"address"},{"indexed":false,"internalType":"uint32","name":"callConfig","type":"uint32"}],"name":"NewDAppSignatory","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"control","type":"address"},{"indexed":true,"internalType":"address","name":"governance","type":"address"},{"indexed":true,"internalType":"address","name":"signatory","type":"address"},{"indexed":false,"internalType":"uint32","name":"callConfig","type":"uint32"}],"name":"RemovedDAppSignatory","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"solverTo","type":"address"},{"indexed":true,"internalType":"address","name":"solverFrom","type":"address"},{"indexed":true,"internalType":"address","name":"dAppControl","type":"address"},{"indexed":false,"internalType":"address","name":"bidToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"executed","type":"bool"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint256","name":"result","type":"uint256"}],"name":"SolverTxResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"currentRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newRecipient","type":"address"}],"name":"SurchargeRecipientTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newRecipient","type":"address"}],"name":"SurchargeRecipientTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SurchargeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"earliestAvailable","type":"uint256"}],"name":"Unbond","type":"event"},{"inputs":[],"name":"ESCROW_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FACTORY_LIB","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FIXED_GAS_OFFSET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L2_GAS_CALCULATOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SCALE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIMULATOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERIFICATION","outputs":[{"internalType":"contract IAtlasVerification","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accessData","outputs":[{"internalType":"uint112","name":"bonded","type":"uint112"},{"internalType":"uint32","name":"lastAccessedBlock","type":"uint32"},{"internalType":"uint24","name":"auctionWins","type":"uint24"},{"internalType":"uint24","name":"auctionFails","type":"uint24"},{"internalType":"uint64","name":"totalGasValueUsed","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accountLastActiveBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"atlasSurchargeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOfBonded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOfUnbonding","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"becomeSurchargeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"bond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bondedTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"bundlerSurchargeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contribute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"control","type":"address"}],"name":"createExecutionEnvironment","outputs":[{"internalType":"address","name":"executionEnvironment","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cumulativeSurcharge","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToBond","type":"uint256"}],"name":"depositAndBond","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint32","name":"callConfig","type":"uint32"},{"internalType":"address","name":"bidToken","type":"address"},{"internalType":"uint32","name":"solverGasLimit","type":"uint32"}],"internalType":"struct DAppConfig","name":"dConfig","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"dapp","type":"address"},{"internalType":"address","name":"control","type":"address"},{"internalType":"uint32","name":"callConfig","type":"uint32"},{"internalType":"address","name":"sessionKey","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"userOp","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"solver","type":"address"},{"internalType":"address","name":"control","type":"address"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"bidToken","type":"address"},{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SolverOperation[]","name":"solverOps","type":"tuple[]"},{"internalType":"address","name":"executionEnvironment","type":"address"},{"internalType":"address","name":"bundler","type":"address"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bool","name":"isSimulation","type":"bool"}],"name":"execute","outputs":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"executionEnvironment","type":"address"},{"internalType":"uint24","name":"solverOutcome","type":"uint24"},{"internalType":"uint8","name":"solverIndex","type":"uint8"},{"internalType":"uint8","name":"solverCount","type":"uint8"},{"internalType":"uint8","name":"callDepth","type":"uint8"},{"internalType":"uint8","name":"phase","type":"uint8"},{"internalType":"bool","name":"solverSuccessful","type":"bool"},{"internalType":"bool","name":"paymentsSuccessful","type":"bool"},{"internalType":"bool","name":"bidFind","type":"bool"},{"internalType":"bool","name":"isSimulation","type":"bool"},{"internalType":"address","name":"bundler","type":"address"}],"internalType":"struct Context","name":"ctx","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"control","type":"address"}],"name":"getExecutionEnvironment","outputs":[{"internalType":"address","name":"executionEnvironment","type":"address"},{"internalType":"uint32","name":"callConfig","type":"uint32"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock","outputs":[{"internalType":"address","name":"activeEnvironment","type":"address"},{"internalType":"uint32","name":"callConfig","type":"uint32"},{"internalType":"uint8","name":"phase","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"dapp","type":"address"},{"internalType":"address","name":"control","type":"address"},{"internalType":"uint32","name":"callConfig","type":"uint32"},{"internalType":"address","name":"sessionKey","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"userOp","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"solver","type":"address"},{"internalType":"address","name":"control","type":"address"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"bidToken","type":"address"},{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SolverOperation[]","name":"solverOps","type":"tuple[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"control","type":"address"},{"internalType":"address","name":"bundler","type":"address"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bytes32","name":"callChainHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct DAppOperation","name":"dAppOp","type":"tuple"},{"internalType":"address","name":"gasRefundBeneficiary","type":"address"}],"name":"metacall","outputs":[{"internalType":"bool","name":"auctionWon","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingSurchargeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxApprovedGasSpend","type":"uint256"}],"name":"reconcile","outputs":[{"internalType":"uint256","name":"owed","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newAtlasRate","type":"uint256"},{"internalType":"uint256","name":"newBundlerRate","type":"uint256"}],"name":"setSurchargeRates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shortfall","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"executionEnvironment","type":"address"},{"internalType":"uint24","name":"solverOutcome","type":"uint24"},{"internalType":"uint8","name":"solverIndex","type":"uint8"},{"internalType":"uint8","name":"solverCount","type":"uint8"},{"internalType":"uint8","name":"callDepth","type":"uint8"},{"internalType":"uint8","name":"phase","type":"uint8"},{"internalType":"bool","name":"solverSuccessful","type":"bool"},{"internalType":"bool","name":"paymentsSuccessful","type":"bool"},{"internalType":"bool","name":"bidFind","type":"bool"},{"internalType":"bool","name":"isSimulation","type":"bool"},{"internalType":"address","name":"bundler","type":"address"}],"internalType":"struct Context","name":"ctx","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"solver","type":"address"},{"internalType":"address","name":"control","type":"address"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"bidToken","type":"address"},{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SolverOperation","name":"solverOp","type":"tuple"},{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"solverCall","outputs":[{"components":[{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"uint256","name":"floor","type":"uint256"},{"internalType":"uint256","name":"ceiling","type":"uint256"},{"internalType":"bool","name":"etherIsBidToken","type":"bool"},{"internalType":"bool","name":"invertsBidValue","type":"bool"}],"internalType":"struct SolverTracker","name":"solverTracker","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"solverLockData","outputs":[{"internalType":"address","name":"currentSolver","type":"address"},{"internalType":"bool","name":"calledBack","type":"bool"},{"internalType":"bool","name":"fulfilled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"opHash","type":"bytes32"}],"name":"solverOpHashes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"surchargeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"control","type":"address"}],"name":"transferDAppERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRecipient","type":"address"}],"name":"transferSurchargeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"control","type":"address"}],"name":"transferUserERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unbond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"unbondingCompleteBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawSurcharge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

610140604052348015610010575f5ffd5b5060405161600138038061600183398101604081905261002f916101cc565b6001600160a01b0380861660805280851660a052821660c05260e0889052808888888888888886868686868686868686868686868686868686868686868686868686868686868686866001600160801b0386118061009357506001600160801b0385115b156100b1576040516359b9784760e01b815260040160405180910390fd5b608086901b851760025534600355600480546001600160a01b0319166001600160a01b0384169081179091556040517f53960c2e64e72b2c1326635f0c002d5cf63e7844d12ed107404693fedde43985905f90a25050505050505050505050505050505050505050505050505050505050505050505050865f036101485760405163b4ff4a4d60e01b815260040160405180910390fd5b5050506001600160a01b0385166101005250506040516101869250469150309060200191825260601b6001600160601b031916602082015260340190565b60408051601f198184030181529190528051602090910120610120525061024a975050505050505050565b80516001600160a01b03811681146101c7575f5ffd5b919050565b5f5f5f5f5f5f5f5f610100898b0312156101e4575f5ffd5b885160208a015160408b01519199509750955061020360608a016101b1565b945061021160808a016101b1565b935061021f60a08a016101b1565b925061022d60c08a016101b1565b915061023b60e08a016101b1565b90509295985092959890939650565b60805160a05160c05160e0516101005161012051615d0e6102f35f395f6139bb01525f818161055a0152613a3801525f818161080301528181611041015281816120ea01528181612fcc01526138ac01525f818161042f015281816109ff01528181610a41015281816147d8015261483101525f818161062b01528181610af20152611be901525f81816105f801528181610b4301528181613ada0152613d7e0152615d0e5ff3fe608060405260043610610251575f3560e01c80638380edb711610137578063c41d54da116100af578063c41d54da146108da578063c5471d9e146108ee578063c5ebeaec14610902578063d0e30db014610915578063d1c23acf1461091d578063d7bb99ba1461093a578063db006a7514610942578063eced552614610961578063f05f88e014610977578063f68b84f71461098a578063f83d08ba1461099d578063fc61c541146109de575f5ffd5b80638380edb714610727578063890c28541461073b5780638ebf091f1461074f57806395d89b4114610763578063966a1f9a146107945780639940686e146107b4578063a0531b02146107d3578063a6efccf9146107f2578063a98efd6714610825578063aa7d2dc81461083c578063aebaa5f714610877578063b2c5c510146108bb575f5ffd5b80635cd6ef67116101ca5780635cd6ef671461041e5780635e8edccc1461045e57806367f7c8e0146105495780636ef5ac7a1461057c57806370a08231146105aa578063791ae748146105e757806379b797651461061a57806379efd1841461064d5780637c20857a1461066d5780637c3c3160146106ae5780637e29c684146106cb578063825ad607146106ea575f5ffd5b806219f2741461025c57806306fdde03146102855780630baf1745146102c657806318160ddd146102e957806319b1faef146102fc578063234b7ede1461031057806327de9e32146103315780632e1a7d4d14610350578063313ce5671461036f5780634511290614610395578063522bc026146103e05780635270182c146103ff575f5ffd5b3661025857005b5f5ffd5b348015610267575f5ffd5b506102726201d4c081565b6040519081526020015b60405180910390f35b348015610290575f5ffd5b506102b960405180604001604052806009815260200168082e8d8c2e6408aa8960bb1b81525081565b60405161027c9190614983565b6102d96102d4366004614a12565b6109fb565b604051901515815260200161027c565b3480156102f4575f5ffd5b505f54610272565b348015610307575f5ffd5b50610272610e8a565b34801561031b575f5ffd5b5061032f61032a366004614abc565b610eb7565b005b34801561033c575f5ffd5b5061032f61034b366004614b12565b610f02565b34801561035b575f5ffd5b5061032f61036a366004614b12565b610f17565b34801561037a575f5ffd5b50610383601281565b60405160ff909116815260200161027c565b3480156103a0575f5ffd5b506103b46103af366004614b29565b610f33565b604080516001600160a01b03909416845263ffffffff909216602084015215159082015260600161027c565b3480156103eb575f5ffd5b5061032f6103fa366004614b6d565b610fbb565b34801561040a575f5ffd5b50610272610419366004614b8d565b611008565b348015610429575f5ffd5b506104517f000000000000000000000000000000000000000000000000000000000000000081565b60405161027c9190614ba8565b348015610469575f5ffd5b50610501610478366004614b8d565b6001600160a01b03165f90815260076020908152604091829020825160a08101845290546001600160701b038116808352600160701b820463ffffffff16938301849052600160901b820462ffffff908116958401869052600160a81b83041660608401819052600160c01b9092046001600160401b0316608090930183905294929392909190565b604080516001600160701b03909616865263ffffffff909416602086015262ffffff928316938501939093521660608301526001600160401b0316608082015260a00161027c565b348015610554575f5ffd5b506104517f000000000000000000000000000000000000000000000000000000000000000081565b348015610587575f5ffd5b506102d9610596366004614b12565b5f9081526008602052604090205460ff1690565b3480156105b5575f5ffd5b506102726105c4366004614b8d565b6001600160a01b03165f908152600660205260409020546001600160701b031690565b3480156105f2575f5ffd5b506104517f000000000000000000000000000000000000000000000000000000000000000081565b348015610625575f5ffd5b506104517f000000000000000000000000000000000000000000000000000000000000000081565b61066061065b366004614c7f565b61106d565b60405161027c9190614e74565b348015610678575f5ffd5b50610272610687366004614b8d565b6001600160a01b03165f90815260076020526040902054600160701b900463ffffffff1690565b3480156106b9575f5ffd5b506005546001600160a01b0316610451565b3480156106d6575f5ffd5b506104516106e5366004614b29565b611160565b3480156106f5575f5ffd5b50610272610704366004614b8d565b6001600160a01b03165f908152600760205260409020546001600160701b031690565b348015610732575f5ffd5b505f5c156102d9565b348015610746575f5ffd5b50600154610272565b34801561075a575f5ffd5b5061032f61121b565b34801561076e575f5ffd5b506102b9604051806040016040528060068152602001650c2e8d88aa8960d31b81525081565b6107a76107a2366004614ef4565b61128f565b60405161027c9190615084565b3480156107bf575f5ffd5b5061032f6107ce366004614b12565b6116d4565b3480156107de575f5ffd5b5061032f6107ed366004614b8d565b6116de565b3480156107fd575f5ffd5b506102727f000000000000000000000000000000000000000000000000000000000000000081565b348015610830575f5ffd5b5060025460801c610272565b348015610847575f5ffd5b5061085061173c565b604080516001600160a01b039094168452911515602084015215159082015260600161027c565b348015610882575f5ffd5b50610272610891366004614b8d565b6001600160a01b03165f90815260066020526040902054600160701b90046001600160701b031690565b3480156108c6575f5ffd5b5061032f6108d5366004614abc565b611752565b3480156108e5575f5ffd5b5061032f611770565b3480156108f9575f5ffd5b50600354610272565b61032f610910366004614b12565b6117c2565b61032f611895565b348015610928575f5ffd5b506002546001600160801b0316610272565b61032f6118a1565b34801561094d575f5ffd5b5061032f61095c366004614b12565b6118d9565b34801561096c575f5ffd5b506102726298968081565b61032f610985366004614b12565b6118eb565b610272610998366004614b12565b6118f5565b3480156109a8575f5ffd5b506109b1611a17565b604080516001600160a01b03909416845263ffffffff909216602084015260ff169082015260600161027c565b3480156109e9575f5ffd5b506004546001600160a01b0316610451565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615610ac2576040516336d2da6b60e21b81523660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063db4b69ac90602401602060405180830381865afa158015610a8e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab29190615092565b5a610abd91906150bd565b610ae5565b610acd6008366150d0565b6152085a610adb91906150bd565b610ae591906150bd565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145f81610b1f5733610b2f565b610b2f60c0870160a08801614b8d565b90505f5f610b3c8b611a2d565b915091505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ab0a4b96838e8e8e8e348b8d6040518963ffffffff1660e01b8152600401610b9b9897969594939291906153d7565b6020604051808303815f875af1158015610bb7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bdb91906154ed565b90505f81601d811115610bf057610bf061550b565b14610c8f578415610c1f5780604051634e47c97160e01b8152600401610c16919061551f565b60405180910390fd5b610c2b60096001615545565b60ff1681601d811115610c4057610c4061550b565b60ff1610158015610c615750610c5f826020015163ffffffff16611b00565b155b15610c74575f9650505050505050610e81565b80604051631eb2e74960e01b8152600401610c16919061551f565b50610c9a8183611b20565b610ca385611b55565b306001600160a01b03166379efd184828d8d8d87898f60c001358c6040518963ffffffff1660e01b8152600401610ce198979695949392919061555e565b610180604051808303815f875af1925050508015610d1c575060408051601f3d908101601f19168201909252610d19918101906155f3565b60015b610de0573d808015610d49576040519150601f19603f3d011682016040523d82523d5f602084013e610d4e565b606091505b50610d5d818360200151611bd3565b610d676008611cf5565b3415610d7757610d773334611d08565b610d8460208d018d614b8d565b604080515f80825260208201819052818301819052606082015290516001600160a01b03929092169133917fde0b67c553d23d5f8bb4c6305ceb7112ee27f974197bee8c02502a7e36cff063919081900360800190a350610e73565b5f5f610df783856060015163ffffffff168c611d21565b60e08501519a509092509050610e1060208f018f614b8d565b610100840151604080518c1515815291151560208301528101849052606081018390526001600160a01b03919091169033907fde0b67c553d23d5f8bb4c6305ceb7112ee27f974197bee8c02502a7e36cff0639060800160405180910390a35050505b610e7b611eb6565b50505050505b95945050505050565b5f5f610e94611ebd565b905060085c808211610ea6575f610eb0565b610eb081836156dc565b9250505090565b610eef828260806020600860025b60ff166001901b60016008811115610edf57610edf61550b565b60ff166001901b17171717611ee6565b610efb85838686611f7a565b5050505050565b610f0a611fc9565b610f143382611fe9565b50565b610f1f611fc9565b610f29338261213e565b610f143382611d08565b5f5f5f836001600160a01b0316638d2129786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f72573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9691906156ef565b9150610fa38585846121a0565b95919450506001600160a01b0385163b151592509050565b610fc3612219565b6001600160801b03821180610fde57506001600160801b0381115b15610ffc576040516359b9784760e01b815260040160405180910390fd5b60809190911b17600255565b6001600160a01b0381165f90815260076020526040812054600160701b900463ffffffff1680820361103c57505f92915050565b6110667f0000000000000000000000000000000000000000000000000000000000000000826150bd565b9392505050565b6110756148c4565b33301461109557604051633006171960e21b815260040160405180910390fd5b6110a28584868986612244565b905060606110b98a6020015163ffffffff166122be565b156110cc576110c9828b8b6122c6565b90505b6110d8828b8b8461242e565b90505f6110ee8b6020015163ffffffff16612602565b61110557611100838c8c8c8c8761260a565b611113565b611113838c8c8c8c87612705565b90508260e001511561112b5761112b838c83856129d1565b61113e8b6020015163ffffffff16612b37565b1561115257611152838460e0015184612b3f565b505098975050505050505050565b5f336001600160a01b038416148015906111835750336001600160a01b03831614155b156111a0576040516282b42960e81b815260040160405180910390fd5b5f826001600160a01b0316638d2129786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111dd573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061120191906156ef565b905061120e848483612c50565b949350505050565b905090565b6005546001600160a01b0316331461124657604051633006171960e21b815260040160405180910390fd5b60048054336001600160a01b031991821681179092556005805490911690556040517f53960c2e64e72b2c1326635f0c002d5cf63e7844d12ed107404693fedde43985905f90a2565b611297614927565b3330146112b75760405163887efaa560e01b815260040160405180910390fd5b60605f6112c76020880188614b8d565b6001600160a01b03168060015d506112e560e0880160c08901614b8d565b6002805c6001600160a01b0319166001600160a01b03831617905d5061130b6003611cf5565b87602001516001600160a01b031686888787604051602401611330949392919061570a565b60408051601f198184030181529190526020810180516001600160e01b03166001626c60f760e01b03191790526113688a6003612ca9565b60405160200161137992919061574c565b60408051601f198184030181529082905261139391615760565b5f604051808303815f865af19150503d805f81146113cc576040519150601f19603f3d011682016040523d82523d5f602084013e6113d1565b606091505b5092509050806113e357815160208301fd5b818060200190518101906113f7919061576b565b92506114036004611cf5565b6114108760400135612d33565b61142d57604051631217157160e31b815260040160405180910390fd5b61152a5a604089013561144360208b018b614b8d565b60208c015161145a6101408d016101208e01614b8d565b8b6114696101608f018f6157e7565b61147c5f5c60081c63ffffffff16612d70565b61149357604080515f8152602081019091526114c9565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050505b6040516024016114df9796959493929190615829565b60408051601f198184030181529190526020810180516001600160e01b0316630120c0d360e11b17905261151960e08c0160c08d01614b8d565b6001600160a01b0316929190612d78565b90508061154a57604051630357b89960e61b815260040160405180910390fd5b6115546005611cf5565b87602001516001600160a01b0316878686866040516024016115799493929190615884565b60408051601f198184030181529190526020810180516001600160e01b0316634667020160e11b1790526115ae8a6005612ca9565b6040516020016115bf92919061574c565b60408051601f19818403018152908290526115d991615760565b5f604051808303815f865af19150503d805f8114611612576040519150601f19603f3d011682016040523d82523d5f602084013e611617565b606091505b50925090508061162957815160208301fd5b8180602001905181019061163d919061576b565b92505f5f611649612d90565b92509250508161166c57604051638ac3609160e01b815260040160405180910390fd5b8015801561167f575061167d612daa565b155b1561169d57604051631d75534f60e01b815260040160405180910390fd5b896101200151156116c757845160405163304680d760e01b81526004810191909152602401610c16565b5050505095945050505050565b610f143382612dbd565b6116e6612219565b600454600580546001600160a01b0319166001600160a01b0384811691821790925560405191909216919082907ffc722bcd56a71612cd14b287fbf50545429e6c9e8de86ea7c3febdecd34882fd905f90a35050565b5f5f5f611747612d90565b925092509250909192565b61176482826080604060206003610ec5565b610efb85828686611f7a565b611778612219565b600380545f90915561178a3382611d08565b60405181815233907f87fa2ce024d3bdae31517696c13905fc0882bc1b4f4508060eb29358056de22b9060200160405180910390a250565b805f036117cc5750565b5f5c602881901c906001600160a01b03821633146117ff57816040516346ba7eb160e11b8152600401610c169190614ba8565b600460ff82161115611824576040516338961af360e21b815260040160405180910390fd5b5f61182d612d90565b509150508015611850576040516338961af360e21b815260040160405180910390fd5b61185984612d33565b1561186d576118683385611d08565b61188f565b60405163029d54f560e21b815247600482015260248101859052604401610c16565b50505050565b61189f3334612ee2565b565b5f5c60281c336001600160a01b038216146118d157806040516346ba7eb160e11b8152600401610c169190614ba8565b610f14612f90565b6118e1611fc9565b610f143382612fae565b6116d43334612ee2565b5f6004815c60ff161461191b576040516338961af360e21b815260040160405180910390fd5b336001600160a01b0360025c161461194657604051633006171960e21b815260040160405180910390fd5b5f5f5f611951612d90565b6001600160a01b0383165f9081526007602052604090205492955090935091506001600160701b031680861115611986578095505b5f61198f611ebd565b90505f61199e3460085c6150bd565b905034156119ad57808060085d505b6119b788826150bd565b8211156119ef57846119d9576001600160a01b038616600160a11b178060015d505b6119e381836156dc565b98975050505050505050565b83611a0a57600360a11b6001600160a01b038716178060015d505b505f979650505050505050565b5f8080805c602881901c90600881901c90611747565b604080516080810182525f8082526020820181905291810182905260608101829052611a6161012084016101008501614b8d565b6001600160a01b03166344912b6e846040518263ffffffff1660e01b8152600401611a8c91906158b9565b608060405180830381865afa158015611aa7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611acb91906158cb565b9050611af9611add6020850185614b8d565b611aef61012086016101008701614b8d565b8360200151612c50565b9150915091565b5f600a5b63ffffffff166001901b8263ffffffff16165f14159050919050565b5f5c15611b3f5760405162dc149f60e41b815260040160405180910390fd5b6020820151611b519082906001613130565b5050565b5f3a611b64836201d4c06150bd565b611b6e91906150d0565b90505f5f611b7a61315c565b9092509050611b898382613173565b8060045d50611b988383613196565b8060055d50348060085d505f8060065d505f8060075d505f8060035d505f8060015d505f6002805c6001600160a01b031916905d5050505050565b5f611bdd83615932565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163303611cba57631b63f4db60e01b6001600160e01b0319821601611c4857825183015160405163e49c0b2560e01b815260048101829052602401610c16565b6001600160e01b03198116635933e62b60e11b1480611c7757506001600160e01b0319811663bdc56ad160e01b145b80611c9257506001600160e01b0319811663a695d44360e01b145b80611cad57506001600160e01b03198116635fd307e960e11b145b15611cba57805f5260045ffd5b6001600160e01b03198116634011dcb760e11b1480611ce35750611ce38263ffffffff16611b00565b15611cf057805f5260045ffd5b505050565b8060ff1660ff195f5c16175f81905d5050565b5f385f3884865af1611b515763b12d13eb5f526004601cfd5b5f5f5f611d2c612d90565b50909150506001600160a01b038416611d485785610160015193505b5f808060085c611d588a8a6131a5565b9850909550935091505f8080611d6e86886156dc565b905084841015611d8957611d8284866156dc565b9250611d96565b611d9385856156dc565b91505b8c60e001518015611dbe57508c61016001516001600160a01b0316886001600160a01b031614155b15611dd757611dcd81846150bd565b9250809950611e04565b8c61016001516001600160a01b0316886001600160a01b031603611dfd575f9950611e04565b5f99508a97505b81831115611e78578c60e00151611e3b57611e1f82846156dc565b6040516306de921b60e51b8152600401610c1691815260200190565b5f611e5289611e4a85876156dc565b84600161334d565b90508a811115611e6657611e1f8b826156dc565b611e70818c6156dc565b9a5050611e8c565b611e8c88611e8685856156dc565b8361363a565b611e966008611cf5565b8915611ea657611ea68b8b611d08565b5050505050505050935093915050565b5f80805d50565b5f60065c60055c611ed260045c60075c6150bd565b611edc91906150bd565b61121691906156dc565b5f5c602881901c90600881901c90336001600160a01b03841614611f1d57604051631e6d8cfb60e21b815260040160405180910390fd5b611f29338787856137c8565b611f46576040516343fcae1b60e01b815260040160405180910390fd5b8360ff168160ff166001901b165f03611f7257604051630106530b60e21b815260040160405180910390fd5b505050505050565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f51141716611fbc57637939f4245f526004601cfd5b5f60605260405250505050565b5f5c1561189f57604051630106530b60e21b815260040160405180910390fd5b5f611ff3826137f2565b6001600160a01b0384165f908152600760205260408120805492935091839183916120289084906001600160701b0316615970565b82546101009290920a6001600160701b03818102199093169183160217909155825463ffffffff60701b1916600160701b4363ffffffff1681029190911784556001600160a01b0387165f90815260066020526040902080548694509092600e926120989286929190041661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550836001600160a01b03167f7659747cd8571f1071eea946fdc648adcf181cad916f32a05f82c3a525976048847f00000000000000000000000000000000000000000000000000000000000000004361211491906150bd565b61211f9060016150bd565b604080519283526020830191909152015b60405180910390a250505050565b6121488282613829565b805f5f82825461215891906156dc565b90915550506040518181526001600160a01b038316907fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5906020015b60405180910390a25050565b5f5f6121ad8585856139b5565b90505f6121f9868686856040516024016121ca94939291906159ae565b60408051601f198184030181529190526020810180516001600160e01b031663d447616160e01b179052613a32565b90508080602001905181019061220f91906159dd565b9695505050505050565b6004546001600160a01b0316331461189f57604051633006171960e21b815260040160405180910390fd5b61224c6148c4565b5060408051610180810182529485526001600160a01b0395861660208601525f9085018190526060850181905260ff92909216608085015260a08401829052600160c085015260e084018290526101008401829052610120840191909152151561014083015290911661016082015290565b5f6002611b04565b606060016122d381611cf5565b5f5f86602001516001600160a01b0316856040516024016122f491906158b9565b60408051601f198184030181529190526020810180516001600160e01b0316630e75dff560e21b179052612329896001612ca9565b60405160200161233a92919061574c565b60408051601f198184030181529082905261235491615760565b5f604051808303815f865af19150503d805f811461238d576040519150601f19603f3d011682016040523d82523d5f602084013e612392565b606091505b509150915081156123e9576123b0866020015163ffffffff16613abd565b156123d257808060200190518101906123c991906159f8565b93505050612426565b5050604080515f8152602081019091529150612426565b8661014001511561240d57604051635933e62b60e11b815260040160405180910390fd5b604051635b47d49f60e11b815260040160405180910390fd5b509392505050565b6060600261243b81611cf5565b5f60605f619c4060405a61245090603f6150d0565b61245a9190615a8a565b61246491906156dc565b905080876060013510612477578061247d565b86606001355b905061248c8760400135612d33565b6124a957604051631217157160e31b815260040160405180910390fd5b88602001516001600160a01b031687604001358290896040516024016124cf91906158b9565b60408051601f198184030181529190526020810180516001600160e01b031663a395822560e01b1790526125048d6002612ca9565b60405160200161251592919061574c565b60408051601f198184030181529082905261252f91615760565b5f60405180830381858888f193505050503d805f811461256a576040519150601f19603f3d011682016040523d82523d5f602084013e61256f565b606091505b50909350915082156125bc5761258e886020015163ffffffff16613ac5565b156125b157818060200190518101906125a791906159f8565b94505050506125f9565b8594505050506125f9565b886101400151156125e05760405163bdc56ad160e01b815260040160405180910390fd5b604051639f885ee560e01b815260040160405180910390fd5b50949350505050565b5f6013611b04565b5f80835b8060ff16896060015160ff161015612695573686868b6060015160ff1681811061263a5761263a615aa9565b905060200281019061264c9190615abd565b90506126628a8a8a848561014001355f8b613acd565b92508960e00151156126795782935050505061220f565b506060890180519061268a82615adc565b60ff1690525061260e565b886101400151156126c657886040015162ffffff1660405163e49c0b2560e01b8152600401610c1691815260200190565b6126d9886020015163ffffffff16613d6d565b156126f757604051634011dcb760e11b815260040160405180910390fd5b505f98975050505050505050565b5f8280820361276e57876101400151156127345760405163e49c0b2560e01b81525f6004820152602401610c16565b612747876020015163ffffffff16613d6d565b1561276557604051634011dcb760e11b815260040160405180910390fd5b5f91505061220f565b60016101208901525f816001600160401b0381111561278f5761278f614bbc565b6040519080825280602002602001820160405280156127b8578160200160208202803683370190505b5090505f806127c86001856156dc565b90505f5a90505f5b8581101561285c576128088d8d8d8d8d868181106127f0576127f0615aa9565b90506020028101906128029190615abd565b8c613d75565b9350831580159061282057506001600160f01b038411155b15612854578061ffff16601085901b1785848151811061284257612842615aa9565b60209081029190910101525f19909201915b6001016127d0565b506128686001866156dc565b915061287384613fc1565b5f6101208d015261288d5a61288890836156dc565b614016565b815b60108582815181106128a3576128a3615aa9565b6020026020010151901c9350835f031561295d576128c181846156dc565b60ff1660608e015284515f9061ffff908790849081106128e3576128e3615aa9565b60200260200101511660ff1690506129248e8e8e8e8e8681811061290957612909615aa9565b905060200281019061291b9190615abd565b8960018f613acd565b94508d60e001511561293f578497505050505050505061220f565b815f0361294c575061295d565b5061295681615afa565b905061288f565b508b61014001511561298f578b6040015162ffffff1660405163e49c0b2560e01b8152600401610c1691815260200190565b6129a28b6020015163ffffffff16613d6d565b156129c057604051634011dcb760e11b815260040160405180910390fd5b505f9b9a5050505050505050505050565b60066129dc81611cf5565b5f5f86602001516001600160a01b031686604001518686604051602401612a0593929190615b0f565b60408051601f198184030181529190526020810180516001600160e01b0316630b65dadf60e11b179052612a3a896006612ca9565b604051602001612a4b92919061574c565b60408051601f1981840301815290829052612a6591615760565b5f604051808303815f865af19150503d805f8114612a9e576040519150601f19603f3d011682016040523d82523d5f602084013e612aa3565b606091505b50915091508115612ac55780806020019051810190612ac29190615b35565b91505b81158015612ae35750612ae1866020015163ffffffff1661404a565b155b15612b245786610140015115612b0c5760405163a695d44360e01b815260040160405180910390fd5b60405162d14f5160e11b815260040160405180910390fd5b5015156101009095019490945250505050565b5f6008611b04565b6007612b4a81611cf5565b5f84602001516001600160a01b03168484604051602401612b6c929190615b50565b60408051601f198184030181529190526020810180516001600160e01b031663b1d5b5a360e01b179052612ba1876007612ca9565b604051602001612bb292919061574c565b60408051601f1981840301815290829052612bcc91615760565b5f604051808303815f865af19150503d805f8114612c05576040519150601f19603f3d011682016040523d82523d5f602084013e612c0a565b606091505b5050905080610efb5784610140015115612c3757604051635fd307e960e11b815260040160405180910390fd5b6040516333c0622b60e11b815260040160405180910390fd5b5f5f612c5d8585856139b5565b90505f6121f986868685604051602401612c7a94939291906159ae565b60408051601f198184030181529190526020810180516001600160e01b0316630cfce7b160e11b179052613a32565b6060816008811115612cbd57612cbd61550b565b60ff1660c084015261016083015160e084015161010085015160608601516080870151866008811115612cf257612cf261550b565b6040808a01516101208b01516101408c01519251612d1c9998979695949390600190602001615b7b565b604051602081830303815290604052905092915050565b5f815f03612d4357506001919050565b81471015612d5257505f919050565b8160075f612d6183835c6150bd565b92505081905d50600192915050565b5f600f611b04565b5f5f5f5f845160208601878a8af19695505050505050565b60015c90600160a11b8216151590600160a21b8316151590565b5f612db3611ebd565b60085c1015905090565b5f612dc7826137f2565b6001600160a01b0384165f90815260066020526040812080549293508392909190612dfc9084906001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550815f5f828254612e3091906156dc565b90915550506001600160a01b0383165f9081526007602052604081208054839290612e659084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b031602179055508160015f828254612e9a91906150bd565b90915550506040518281526001600160a01b038416907f6b1d99469ed62a423d7e402bfa68a467261ca2229127c55045ee41e5d9a0f21d9060200160405180910390a2505050565b805f5f828254612ef291906150bd565b90915550612f019050816137f2565b6001600160a01b0383165f9081526006602052604081208054909190612f319084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550816001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858260405161219491815260200190565b341561189f573460085f612fa583835c6150bd565b92505081905d50565b6001600160a01b0382165f90815260076020526040902054612ffe907f000000000000000000000000000000000000000000000000000000000000000090600160701b900463ffffffff166150bd565b431161301d5760405163078e135760e51b815260040160405180910390fd5b5f613027826137f2565b6001600160a01b0384165f90815260066020526040902080549192509082908290600e90613066908490600160701b90046001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b031602179055508260015f82825461309b91906156dc565b90915550508054829082905f906130bc9084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550825f5f8282546130f091906150bd565b90915550506040518381526001600160a01b038516907f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a690602001612130565b600160281b600160c81b03602884901b1664ffffffff00600884901b161760ff821617805f5d50505050565b600254608081901c916001600160801b0390911690565b5f6298968061318283826150bd565b61318c90856150d0565b6110669190615a8a565b5f6298968061318c83856150d0565b60035460075c9060045c9060065c905f9060055c82806131c361315c565b915091505f5a90505f6131d63a836150d0565b90506131e28184613173565b6131ec908a6156dc565b98508b60e001511561322c576132028185613196565b61320c90866156dc565b9650613218878b6150bd565b995061322487876150bd565b6003556132b6565b60035c80156132aa5761324b8561324386826150bd565b839190614052565b97505f61325889836156dc565b90505f61326d6132688d88614068565b614083565b90508082111561328e5761328181836156dc565b61328b908b6150bd565b99505b6132988a8e6150bd565b9c506132a48a8a6150bd565b60035550505b50505050505050613344565b60808c015160ff161561333d575f6132ce8a85614068565b90505f6207a1208e606001518f608001516132e99190615c1c565b6132f69060ff168f6150d0565b61330091906150bd565b90508084111561333a575f8461331683856150d0565b6133209190615a8a565b61332a90846156dc565b9050613336818c6150bd565b9a50505b50505b5050505050505b92959194509250565b5f5f613358856137f2565b6001600160a01b0387165f90815260076020908152604091829020825160a08101845290546001600160701b0380821680845263ffffffff600160701b8404169484019490945262ffffff600160901b8304811695840195909552600160a81b820490941660608301526001600160401b03600160c01b909104166080820152929350908316111561350f576001600160a01b0387165f9081526006602090815260408083208151808301909252546001600160701b038082168352600160701b9091048116928201839052845191939261343692909116906150bd565b905080846001600160701b031611156134a95761345381896156dc565b6001600160a01b038a165f90815260066020819052604082208054600160701b600160e01b031916905581865291965086919061349183835c6150bd565b92505081905d506134a285896156dc565b9750613508565b6134c46134bf6001600160701b038616836156dc565b6137f2565b6001600160a01b038a165f90815260066020526040812080546001600160701b0393909316600160701b02600160701b600160e01b03199093169290921790915583525b505061352d565b81815f018181516135209190615970565b6001600160701b03169052505b6135428185801561353c575084155b876140a5565b63ffffffff43811660208084019182526001600160a01b038a165f9081526007909152604080822085518154945192870151606088015160808901516001600160401b0316600160c01b026001600160c01b0362ffffff928316600160a81b0262ffffff60a81b1993909416600160901b029290921665ffffffffffff60901b1996909916600160701b026001600160901b03199098166001600160701b03909416939093179690961793909316959095179190911792909216929092179055600180548892906136149084906156dc565b9091555086905060085f61362983835c6150bd565b92505081905d505050949350505050565b6001600160a01b0383165f90815260076020908152604091829020825160a08101845290546001600160701b0381168252600160901b810462ffffff90811694830194909452600160a81b81049093166060820152600160c01b9092046001600160401b0316608083015263ffffffff4316908201526136b9836137f2565b815182906136c890839061598f565b6001600160701b0316905250600180548491905f906136e89084906150bd565b909155506136fa9050816001846140a5565b6001600160a01b0384165f908152600760208181526040808420855181549387015192870151606088015160808901516001600160701b039093166001600160901b031990961695909517600160701b63ffffffff909516949094029390931765ffffffffffff60901b1916600160901b62ffffff9485160262ffffff60a81b191617600160a81b9390941692909202929092176001600160c01b0316600160c01b6001600160401b039092169190910217905584916137bb83835c6150bd565b92505081905d5050505050565b5f6137d48484846121a0565b6001600160a01b0316856001600160a01b0316149050949350505050565b5f6001600160701b03821115613825576040516306dfcc6560e41b81526070600482015260248101839052604401610c16565b5090565b5f613833826137f2565b6001600160a01b0384165f9081526006602052604090208054919250906001600160701b03908116908316811061388e5761386e8382615970565b82546001600160701b0319166001600160701b0391909116178255610efb565b6001600160a01b0385165f908152600760205260409020546138de907f000000000000000000000000000000000000000000000000000000000000000090600160701b900463ffffffff166150bd565b43111561398a575f6138f08285615970565b83546001600160701b03191680855590915081908490600e90613924908490600160701b90046001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505f816001600160701b03169050805f5f82825461396591906150bd565b925050819055508060015f82825461397d91906156dc565b90915550610efb92505050565b6040516307d2457d60e21b81526001600160701b038216600482015260248101859052604401610c16565b604080517f0000000000000000000000000000000000000000000000000000000000000000602080830191909152606095861b6001600160601b0319908116838501529490951b909316605484015260e09190911b6001600160e01b03191660688301528051604c818403018152606c9092019052805191012090565b60605f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684604051613a6e9190615760565b5f60405180830381855af49150503d805f8114613aa6576040519150601f19603f3d011682016040523d82523d5f602084013e613aab565b606091505b50915091508161106657805160208201fd5b5f6003611b04565b5f6004611b04565b5f5f5a90505f84613bae577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639f7e72b6888c5f01518b608001358e6101600151613b2a8f6020015163ffffffff16614109565b6040518663ffffffff1660e01b8152600401613b4a959493929190615c35565b602060405180830381865afa158015613b65573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b899190615092565b9050613bab613ba061014089016101208a01614b8d565b8a6040015183614111565b90505b80613cb3575f613bc08a89858561413d565b9092509050613bcf888b614246565b82179150613be08a878b8b866142d8565b915081613cb157613bef614927565b613bfc8c8a8a858a61431a565b909350905082613caf578a516001600160a01b0316613c1e60208b018b614b8d565b6001600160a01b0316613c3760e08c0160c08d01614b8d565b6001600160a01b03167f94e79da376f3bc5202c947c2466a329832d3e9af2f4e094a18c160868453273c613c736101408e016101208f01614b8d565b8c6001808a604051613c89959493929190615c76565b60405180910390a4600160e08d015262ffffff90921660408c015250519150613d629050565b505b505b62ffffff811660408b0152613ccb8783838815614550565b88516001600160a01b0316613ce36020890189614b8d565b6001600160a01b0316613cfc60e08a0160c08b01614b8d565b6001600160a01b03167f94e79da376f3bc5202c947c2466a329832d3e9af2f4e094a18c160868453273c613d386101408c016101208d01614b8d565b8a62fe0000871615155f88604051613d54959493929190615c76565b60405180910390a45f925050505b979650505050505050565b5f6010611b04565b5f5f5a90505f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639f7e72b6878b5f01518a608001358d6101600151613dce8e6020015163ffffffff16614109565b6040518663ffffffff1660e01b8152600401613dee959493929190615c35565b602060405180830381865afa158015613e09573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e2d9190615092565b9050613e4f613e4461014088016101208901614b8d565b896040015183614111565b9050613e5d8887858461413d565b92509050613e6b8689614246565b178015613e7d575f9350505050610e81565b613e90886020015163ffffffff16614109565b15613eae57613e9f8787614640565b613eae575f9350505050610e81565b5f5f306001600160a01b031684306001600160a01b031663966a1f9a8e8c8d61014001358d604051602401613ee69493929190615ca6565b60408051601f198184030181529181526020820180516001600160e01b031660e09490941b939093179092529051613f1e9250615760565b5f604051808303815f8787f1925050503d805f8114613f58576040519150601f19603f3d011682016040523d82523d5f602084013e613f5d565b606091505b50915091508115613f815760405163039f249b60e61b815260040160405180910390fd5b63304680d760e01b613f9282615932565b6001600160e01b03191603613fb157805101519450610e819350505050565b505f9a9950505050505050505050565b80515f82528060051b8201601f19602084015b60200182811161400f5780518282018051828111613ff457505050613fd4565b5b602082015283018051828111613ff5575060200152613fd4565b5050509052565b5f5f61402061315c565b9092509050614030838383614756565b60065f61403e83835c6150bd565b92505081905d50505050565b5f6014611b04565b5f8161405e84866150d0565b61120e9190615a8a565b5f61407682629896806150bd565b61318c62989680856150d0565b5f62989680614095627a1200846150d0565b61409f9190615a8a565b92915050565b81156140c05760408301805160010162ffffff1690526140d1565b60608301805160010162ffffff1690525b6140e76140e2633b9aca0083615a8a565b61477a565b836080018181516140f89190615ce2565b6001600160401b0316905250505050565b5f6011611b04565b5f826001600160a01b0316846001600160a01b03161461413657506108008117611066565b5092915050565b5f5f856060015163ffffffff166207a12061415891906150bd565b84101561416e576020929092179182915061423d565b6201e84861418a8660600135886060015163ffffffff166147af565b61419491906150bd565b90505f6141af6141a86101608801886157e7565b90506147d5565b6141b9833a6150d0565b6141c391906150bd565b905047866040013511156141e25750618000929092179182915061423d565b6141ef6201e848836156dc565b91505f60078161420260208a018a614b8d565b6001600160a01b0316815260208101919091526040015f20546001600160701b03169050808211156142375761200094909417935b84935050505b94509492505050565b5f60a08301351580159061425d57508260a0013543115b1561428d57614275826020015163ffffffff16614109565b614280576008614283565b60025b6001901b1761409f565b5f60078161429e6020870187614b8d565b6001600160a01b0316815260208101919091526040015f2054600160701b900463ffffffff16905043811061413657506110001792915050565b5f6142ec866020015163ffffffff16614109565b80156142f6575084155b801561430957506143078484614640565b155b156125f95750608017949350505050565b5f614323614927565b5f5f306001600160a01b031686306001600160a01b031663966a1f9a8c8c8c8b6040516024016143569493929190615ca6565b60408051601f198184030181529181526020820180516001600160e01b031660e09490941b93909317909252905161438e9250615760565b5f604051808303815f8787f1925050503d805f81146143c8576040519150601f19603f3d011682016040523d82523d5f602084013e6143cd565b606091505b509150915081156143f357808060200190518101906143ec919061576b565b9250614544565b5f6143fd82615932565b90506353068ee960e11b6001600160e01b03198216016144255760065b6001901b9450614542565b630de8ea8f60e31b6001600160e01b031982160161444457600d61441a565b6317f387a160e21b6001600160e01b031982160161446357601061441a565b62a8476760e61b6001600160e01b031982160161448157601161441a565b633277ac1760e21b6001600160e01b03198216016144a057601261441a565b6305bb473560e21b6001600160e01b03198216016144bf57601361441a565b6350dbf98960e01b6001600160e01b03198216016144de57600a61441a565b63e28aacb160e01b6001600160e01b03198216016144fd57601561441a565b63753c9f6f60e01b6001600160e01b031982160161451c57601661441a565b637781055b60e01b6001600160e01b031982160161453b57600661441a565b6280000094505b505b50509550959350505050565b5f3a5a61455f611388876150bd565b61456991906156dc565b61457391906150d0565b90505f5f61457f61315c565b9150915083156145a75761459a6141a86101608901896157e7565b6145a490846150bd565b92505b60ff8516156145d5576145bb838383614756565b60065f6145c983835c6150bd565b92505081905d50614637565b5f6145e1848484614756565b90505f6145ee85836156dc565b90505f61460961460160208c018c614b8d565b84855f61334d565b9050808211156146335761461d81836156dc565b60035f61462b83835c6150bd565b92505081905d505b5050505b50505050505050565b5f614652610100830160e08401614b8d565b6001600160a01b031661466d61012085016101008601614b8d565b6001600160a01b03161461468257505f61409f565b60c08301351580614695575060a0820135155b806146a757508260c001358260a00135145b6146b257505f61409f565b5f6101008301356146c66020850185614b8d565b8460a001356040516020016146fb9392919092835260609190911b6001600160601b0319166020830152603482015260540190565b60408051601f1981840301815291815281516020928301205f818152600890935291205490915060ff1615614733575f91505061409f565b5f908152600860205260409020805460ff19166001908117909155905092915050565b5f629896808261476685836150bd565b61477091906150bd565b61405e90866150d0565b5f6001600160401b0382111561382557604080516306dfcc6560e41b8152600481019190915260248101839052604401610c16565b5f6147c06207a120629896806150bd565b629896808385106131825761318c90846150d0565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614827573a6008614813610260856150bd565b61481d91906150d0565b61409f91906150d0565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016632c652d89614862610260856150bd565b6040518263ffffffff1660e01b815260040161488091815260200190565b602060405180830381865afa15801561489b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061409f9190615092565b919050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040518060a001604052805f81526020015f81526020015f81526020015f151581526020015f151581525090565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6110666020830184614955565b5f6101a082840312156149a6575f5ffd5b50919050565b5f5f83601f8401126149bc575f5ffd5b5081356001600160401b038111156149d2575f5ffd5b6020830191508360208260051b85010111156149ec575f5ffd5b9250929050565b6001600160a01b0381168114610f14575f5ffd5b80356148bf816149f3565b5f5f5f5f5f60808688031215614a26575f5ffd5b85356001600160401b03811115614a3b575f5ffd5b614a4788828901614995565b95505060208601356001600160401b03811115614a62575f5ffd5b614a6e888289016149ac565b90955093505060408601356001600160401b03811115614a8c575f5ffd5b86016101208189031215614a9e575f5ffd5b91506060860135614aae816149f3565b809150509295509295909350565b5f5f5f5f5f60a08688031215614ad0575f5ffd5b8535614adb816149f3565b94506020860135614aeb816149f3565b9350604086013592506060860135614b02816149f3565b91506080860135614aae816149f3565b5f60208284031215614b22575f5ffd5b5035919050565b5f5f60408385031215614b3a575f5ffd5b8235614b45816149f3565b91506020830135614b55816149f3565b809150509250929050565b6001600160a01b03169052565b5f5f60408385031215614b7e575f5ffd5b50508035926020909101359150565b5f60208284031215614b9d575f5ffd5b8135611066816149f3565b6001600160a01b0391909116815260200190565b634e487b7160e01b5f52604160045260245ffd5b604051608081016001600160401b0381118282101715614bf257614bf2614bbc565b60405290565b60405161018081016001600160401b0381118282101715614bf257614bf2614bbc565b604051601f8201601f191681016001600160401b0381118282101715614c4357614c43614bbc565b604052919050565b63ffffffff81168114610f14575f5ffd5b80356148bf81614c4b565b8015158114610f14575f5ffd5b80356148bf81614c67565b5f5f5f5f5f5f5f5f888a03610140811215614c98575f5ffd5b6080811215614ca5575f5ffd5b50614cae614bd0565b8935614cb9816149f3565b815260208a0135614cc981614c4b565b602082015260408a0135614cdc816149f3565b604082015260608a0135614cef81614c4b565b6060820152975060808901356001600160401b03811115614d0e575f5ffd5b614d1a8b828c01614995565b97505060a08901356001600160401b03811115614d35575f5ffd5b614d418b828c016149ac565b9097509550614d54905060c08a01614a07565b9350614d6260e08a01614a07565b92506101008901359150614d796101208a01614c74565b90509295985092959890939650565b805182526020810151614d9e6020840182614b60565b506040810151614db5604084018262ffffff169052565b506060810151614dca606084018260ff169052565b506080810151614ddf608084018260ff169052565b5060a0810151614df460a084018260ff169052565b5060c0810151614e0960c084018260ff169052565b5060e0810151614e1d60e084018215159052565b50610100810151614e3361010084018215159052565b50610120810151614e4961012084018215159052565b50610140810151614e5f61014084018215159052565b50610160810151611cf0610160840182614b60565b610180810161409f8284614d88565b62ffffff81168114610f14575f5ffd5b80356148bf81614e83565b60ff81168114610f14575f5ffd5b80356148bf81614e9e565b5f5f83601f840112614ec7575f5ffd5b5081356001600160401b03811115614edd575f5ffd5b6020830191508360208285010111156149ec575f5ffd5b5f5f5f5f5f8587036101e0811215614f0a575f5ffd5b610180811215614f18575f5ffd5b50614f21614bf8565b86358152614f3160208801614a07565b6020820152614f4260408801614e93565b6040820152614f5360608801614eac565b6060820152614f6460808801614eac565b6080820152614f7560a08801614eac565b60a0820152614f8660c08801614eac565b60c0820152614f9760e08801614c74565b60e0820152614fa96101008801614c74565b610100820152614fbc6101208801614c74565b610120820152614fcf6101408801614c74565b610140820152614fe26101608801614a07565b61016082015294506101808601356001600160401b03811115615003575f5ffd5b61500f88828901614995565b9450506101a086013592506101c08601356001600160401b03811115615033575f5ffd5b61503f88828901614eb7565b969995985093965092949392505050565b8051825260208101516020830152604081015160408301526060810151151560608301526080810151151560808301525050565b60a0810161409f8284615050565b5f602082840312156150a2575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561409f5761409f6150a9565b808202811582820484141761409f5761409f6150a9565b60018060a01b03815116825263ffffffff602082015116602083015260018060a01b03604082015116604083015263ffffffff60608201511660608301525050565b5f5f8335601e1984360301811261513e575f5ffd5b83016020810192503590506001600160401b0381111561515c575f5ffd5b8036038213156149ec575f5ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6151a48261519f83614a07565b614b60565b5f6151b160208301614a07565b6151be6020850182614b60565b5060408281013590840152606080830135908401526080808301359084015260a0808301359084015260c080830135908401526151fd60e08301614a07565b61520a60e0850182614b60565b506152186101008301614a07565b615226610100850182614b60565b506152346101208301614c5c565b63ffffffff1661012084015261524d6101408301614a07565b61525b610140850182614b60565b5061526a610160830183615129565b6101a06101608601526152826101a08601828461516a565b915050615293610180840184615129565b85830361018087015261220f83828461516a565b6152b48261519f83614a07565b5f6152c160208301614a07565b6152ce6020850182614b60565b5060408281013590840152606080830135908401526080808301359084015260a0808301359084015261530360c08301614a07565b61531060c0850182614b60565b5061531d60e08301614a07565b61532a60e0850182614b60565b5061010082810135908401526153436101208301614a07565b615351610120850182614b60565b50610140828101359084015261526a610160830183615129565b5f8383855260208501945060208460051b820101835f5b868110156153cb57838303601f1901885281353687900361019e190181126153a8575f5ffd5b6153b4848883016152a7565b6020998a0199909450929092019150600101615382565b50909695505050505050565b6153e1818a6150e7565b61014060808201525f6153f861014083018a615192565b82810360a084015261540b81898b61536b565b905082810360c08401526154228161519f89614a07565b61542e60208801614a07565b61543b6020830182614b60565b50604087810135908201526060808801359082015261545c60808801614a07565b6154696080830182614b60565b5061547660a08801614a07565b61548360a0830182614b60565b5060c0878101359082015260e080880135908201526154a6610100880188615129565b6101206101008401526154be6101208401828461516a565b93505050508460e08301526154d7610100830185614b60565b8215156101208301529998505050505050505050565b5f602082840312156154fd575f5ffd5b8151601e8110611066575f5ffd5b634e487b7160e01b5f52602160045260245ffd5b60208101601e831061553f57634e487b7160e01b5f52602160045260245ffd5b91905290565b60ff818116838216019081111561409f5761409f6150a9565b615568818a6150e7565b61014060808201525f61557f61014083018a615192565b82810360a084015261559281898b61536b565b6001600160a01b0397881660c08501529590961660e08301525061010081019290925215156101209091015295945050505050565b80516148bf816149f3565b80516148bf81614e83565b80516148bf81614e9e565b80516148bf81614c67565b5f610180828403128015615605575f5ffd5b5061560e614bf8565b8251815261561e602084016155c7565b602082015261562f604084016155d2565b6040820152615640606084016155dd565b6060820152615651608084016155dd565b608082015261566260a084016155dd565b60a082015261567360c084016155dd565b60c082015261568460e084016155e8565b60e082015261569661010084016155e8565b6101008201526156a961012084016155e8565b6101208201526156bc61014084016155e8565b6101408201526156cf61016084016155c7565b6101608201529392505050565b8181038181111561409f5761409f6150a9565b5f602082840312156156ff575f5ffd5b815161106681614c4b565b848152606060208201525f61572260608301866152a7565b8281036040840152613d6281858761516a565b5f81518060208401855e5f93019283525090919050565b5f61120e61575a8386615735565b84615735565b5f6110668284615735565b5f60a082840312801561577c575f5ffd5b5060405160a081016001600160401b038111828210171561579f5761579f614bbc565b60409081528351825260208085015190830152838101519082015260608301516157c881614c67565b606082015260808301516157db81614c67565b60808201529392505050565b5f5f8335601e198436030181126157fc575f5ffd5b8301803591506001600160401b03821115615815575f5ffd5b6020019150368190038213156149ec575f5ffd5b6001600160a01b0388811682528781166020830152861660408201526060810185905260c0608082018190525f90615864908301858761516a565b82810360a08401526158768185614955565b9a9950505050505050505050565b60e081525f61589660e08301876152a7565b82810360208401526158a981868861516a565b915050610e816040830184615050565b602081525f6110666020830184615192565b5f60808284031280156158dc575f5ffd5b506158e5614bd0565b82516158f0816149f3565b8152602083015161590081614c4b565b60208201526040830151615913816149f3565b6040820152606083015161592681614c4b565b60608201529392505050565b805160208201516001600160e01b0319811691906004821015615969576001600160e01b0319600483900360031b81901b82161692505b5050919050565b6001600160701b03828116828216039081111561409f5761409f6150a9565b6001600160701b03818116838216019081111561409f5761409f6150a9565b6001600160a01b03948516815292909316602083015263ffffffff166040820152606081019190915260800190565b5f602082840312156159ed575f5ffd5b8151611066816149f3565b5f60208284031215615a08575f5ffd5b81516001600160401b03811115615a1d575f5ffd5b8201601f81018413615a2d575f5ffd5b80516001600160401b03811115615a4657615a46614bbc565b615a59601f8201601f1916602001614c1b565b818152856020838501011115615a6d575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f82615aa457634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b5f823561019e19833603018112615ad2575f5ffd5b9190910192915050565b5f60ff821660ff8103615af157615af16150a9565b60010192915050565b5f81615b0857615b086150a9565b505f190190565b60018060a01b0384168152826020820152606060408201525f610e816060830184614955565b5f60208284031215615b45575f5ffd5b815161106681614c67565b8215158152604060208201525f61120e6040830184614955565b60f81b6001600160f81b0319169052565b60608b901b6001600160601b031916815289151560f890811b6014830152891515811b601583015288901b6001600160f81b0319166016820152615bc26017820188615b6a565b615bcf6018820187615b6a565b615be8601982018660e81b6001600160e81b0319169052565b83151560f81b601c82015282151560f81b601d820152615c0b601e820183615b6a565b601f019a9950505050505050505050565b60ff828116828216039081111561409f5761409f6150a9565b60a081525f615c4760a08301886152a7565b60208301969096525060408101939093526001600160a01b039190911660608301521515608090910152919050565b6001600160a01b039590951685526020850193909352901515604084015215156060830152608082015260a00190565b615cb08186614d88565b6101e06101808201525f615cc86101e08301866152a7565b846101a08401528281036101c0840152613d628185614955565b6001600160401b03818116838216019081111561409f5761409f6150a956fea164736f6c634300081c000a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000001e8480000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e9000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b00000000000000000000000078c5d8df575098a97a3bd1f8dcceb22d71f3a4740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a70aaf5dd6b3b7f06617780c964f2638f24394bf

Deployed Bytecode

0x608060405260043610610251575f3560e01c80638380edb711610137578063c41d54da116100af578063c41d54da146108da578063c5471d9e146108ee578063c5ebeaec14610902578063d0e30db014610915578063d1c23acf1461091d578063d7bb99ba1461093a578063db006a7514610942578063eced552614610961578063f05f88e014610977578063f68b84f71461098a578063f83d08ba1461099d578063fc61c541146109de575f5ffd5b80638380edb714610727578063890c28541461073b5780638ebf091f1461074f57806395d89b4114610763578063966a1f9a146107945780639940686e146107b4578063a0531b02146107d3578063a6efccf9146107f2578063a98efd6714610825578063aa7d2dc81461083c578063aebaa5f714610877578063b2c5c510146108bb575f5ffd5b80635cd6ef67116101ca5780635cd6ef671461041e5780635e8edccc1461045e57806367f7c8e0146105495780636ef5ac7a1461057c57806370a08231146105aa578063791ae748146105e757806379b797651461061a57806379efd1841461064d5780637c20857a1461066d5780637c3c3160146106ae5780637e29c684146106cb578063825ad607146106ea575f5ffd5b806219f2741461025c57806306fdde03146102855780630baf1745146102c657806318160ddd146102e957806319b1faef146102fc578063234b7ede1461031057806327de9e32146103315780632e1a7d4d14610350578063313ce5671461036f5780634511290614610395578063522bc026146103e05780635270182c146103ff575f5ffd5b3661025857005b5f5ffd5b348015610267575f5ffd5b506102726201d4c081565b6040519081526020015b60405180910390f35b348015610290575f5ffd5b506102b960405180604001604052806009815260200168082e8d8c2e6408aa8960bb1b81525081565b60405161027c9190614983565b6102d96102d4366004614a12565b6109fb565b604051901515815260200161027c565b3480156102f4575f5ffd5b505f54610272565b348015610307575f5ffd5b50610272610e8a565b34801561031b575f5ffd5b5061032f61032a366004614abc565b610eb7565b005b34801561033c575f5ffd5b5061032f61034b366004614b12565b610f02565b34801561035b575f5ffd5b5061032f61036a366004614b12565b610f17565b34801561037a575f5ffd5b50610383601281565b60405160ff909116815260200161027c565b3480156103a0575f5ffd5b506103b46103af366004614b29565b610f33565b604080516001600160a01b03909416845263ffffffff909216602084015215159082015260600161027c565b3480156103eb575f5ffd5b5061032f6103fa366004614b6d565b610fbb565b34801561040a575f5ffd5b50610272610419366004614b8d565b611008565b348015610429575f5ffd5b506104517f000000000000000000000000000000000000000000000000000000000000000081565b60405161027c9190614ba8565b348015610469575f5ffd5b50610501610478366004614b8d565b6001600160a01b03165f90815260076020908152604091829020825160a08101845290546001600160701b038116808352600160701b820463ffffffff16938301849052600160901b820462ffffff908116958401869052600160a81b83041660608401819052600160c01b9092046001600160401b0316608090930183905294929392909190565b604080516001600160701b03909616865263ffffffff909416602086015262ffffff928316938501939093521660608301526001600160401b0316608082015260a00161027c565b348015610554575f5ffd5b506104517f000000000000000000000000a70aaf5dd6b3b7f06617780c964f2638f24394bf81565b348015610587575f5ffd5b506102d9610596366004614b12565b5f9081526008602052604090205460ff1690565b3480156105b5575f5ffd5b506102726105c4366004614b8d565b6001600160a01b03165f908152600660205260409020546001600160701b031690565b3480156105f2575f5ffd5b506104517f000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e981565b348015610625575f5ffd5b506104517f000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b81565b61066061065b366004614c7f565b61106d565b60405161027c9190614e74565b348015610678575f5ffd5b50610272610687366004614b8d565b6001600160a01b03165f90815260076020526040902054600160701b900463ffffffff1690565b3480156106b9575f5ffd5b506005546001600160a01b0316610451565b3480156106d6575f5ffd5b506104516106e5366004614b29565b611160565b3480156106f5575f5ffd5b50610272610704366004614b8d565b6001600160a01b03165f908152600760205260409020546001600160701b031690565b348015610732575f5ffd5b505f5c156102d9565b348015610746575f5ffd5b50600154610272565b34801561075a575f5ffd5b5061032f61121b565b34801561076e575f5ffd5b506102b9604051806040016040528060068152602001650c2e8d88aa8960d31b81525081565b6107a76107a2366004614ef4565b61128f565b60405161027c9190615084565b3480156107bf575f5ffd5b5061032f6107ce366004614b12565b6116d4565b3480156107de575f5ffd5b5061032f6107ed366004614b8d565b6116de565b3480156107fd575f5ffd5b506102727f000000000000000000000000000000000000000000000000000000000000004081565b348015610830575f5ffd5b5060025460801c610272565b348015610847575f5ffd5b5061085061173c565b604080516001600160a01b039094168452911515602084015215159082015260600161027c565b348015610882575f5ffd5b50610272610891366004614b8d565b6001600160a01b03165f90815260066020526040902054600160701b90046001600160701b031690565b3480156108c6575f5ffd5b5061032f6108d5366004614abc565b611752565b3480156108e5575f5ffd5b5061032f611770565b3480156108f9575f5ffd5b50600354610272565b61032f610910366004614b12565b6117c2565b61032f611895565b348015610928575f5ffd5b506002546001600160801b0316610272565b61032f6118a1565b34801561094d575f5ffd5b5061032f61095c366004614b12565b6118d9565b34801561096c575f5ffd5b506102726298968081565b61032f610985366004614b12565b6118eb565b610272610998366004614b12565b6118f5565b3480156109a8575f5ffd5b506109b1611a17565b604080516001600160a01b03909416845263ffffffff909216602084015260ff169082015260600161027c565b3480156109e9575f5ffd5b506004546001600160a01b0316610451565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615610ac2576040516336d2da6b60e21b81523660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063db4b69ac90602401602060405180830381865afa158015610a8e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab29190615092565b5a610abd91906150bd565b610ae5565b610acd6008366150d0565b6152085a610adb91906150bd565b610ae591906150bd565b9050336001600160a01b037f000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b16145f81610b1f5733610b2f565b610b2f60c0870160a08801614b8d565b90505f5f610b3c8b611a2d565b915091505f7f000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e96001600160a01b031663ab0a4b96838e8e8e8e348b8d6040518963ffffffff1660e01b8152600401610b9b9897969594939291906153d7565b6020604051808303815f875af1158015610bb7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bdb91906154ed565b90505f81601d811115610bf057610bf061550b565b14610c8f578415610c1f5780604051634e47c97160e01b8152600401610c16919061551f565b60405180910390fd5b610c2b60096001615545565b60ff1681601d811115610c4057610c4061550b565b60ff1610158015610c615750610c5f826020015163ffffffff16611b00565b155b15610c74575f9650505050505050610e81565b80604051631eb2e74960e01b8152600401610c16919061551f565b50610c9a8183611b20565b610ca385611b55565b306001600160a01b03166379efd184828d8d8d87898f60c001358c6040518963ffffffff1660e01b8152600401610ce198979695949392919061555e565b610180604051808303815f875af1925050508015610d1c575060408051601f3d908101601f19168201909252610d19918101906155f3565b60015b610de0573d808015610d49576040519150601f19603f3d011682016040523d82523d5f602084013e610d4e565b606091505b50610d5d818360200151611bd3565b610d676008611cf5565b3415610d7757610d773334611d08565b610d8460208d018d614b8d565b604080515f80825260208201819052818301819052606082015290516001600160a01b03929092169133917fde0b67c553d23d5f8bb4c6305ceb7112ee27f974197bee8c02502a7e36cff063919081900360800190a350610e73565b5f5f610df783856060015163ffffffff168c611d21565b60e08501519a509092509050610e1060208f018f614b8d565b610100840151604080518c1515815291151560208301528101849052606081018390526001600160a01b03919091169033907fde0b67c553d23d5f8bb4c6305ceb7112ee27f974197bee8c02502a7e36cff0639060800160405180910390a35050505b610e7b611eb6565b50505050505b95945050505050565b5f5f610e94611ebd565b905060085c808211610ea6575f610eb0565b610eb081836156dc565b9250505090565b610eef828260806020600860025b60ff166001901b60016008811115610edf57610edf61550b565b60ff166001901b17171717611ee6565b610efb85838686611f7a565b5050505050565b610f0a611fc9565b610f143382611fe9565b50565b610f1f611fc9565b610f29338261213e565b610f143382611d08565b5f5f5f836001600160a01b0316638d2129786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f72573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9691906156ef565b9150610fa38585846121a0565b95919450506001600160a01b0385163b151592509050565b610fc3612219565b6001600160801b03821180610fde57506001600160801b0381115b15610ffc576040516359b9784760e01b815260040160405180910390fd5b60809190911b17600255565b6001600160a01b0381165f90815260076020526040812054600160701b900463ffffffff1680820361103c57505f92915050565b6110667f0000000000000000000000000000000000000000000000000000000000000040826150bd565b9392505050565b6110756148c4565b33301461109557604051633006171960e21b815260040160405180910390fd5b6110a28584868986612244565b905060606110b98a6020015163ffffffff166122be565b156110cc576110c9828b8b6122c6565b90505b6110d8828b8b8461242e565b90505f6110ee8b6020015163ffffffff16612602565b61110557611100838c8c8c8c8761260a565b611113565b611113838c8c8c8c87612705565b90508260e001511561112b5761112b838c83856129d1565b61113e8b6020015163ffffffff16612b37565b1561115257611152838460e0015184612b3f565b505098975050505050505050565b5f336001600160a01b038416148015906111835750336001600160a01b03831614155b156111a0576040516282b42960e81b815260040160405180910390fd5b5f826001600160a01b0316638d2129786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111dd573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061120191906156ef565b905061120e848483612c50565b949350505050565b905090565b6005546001600160a01b0316331461124657604051633006171960e21b815260040160405180910390fd5b60048054336001600160a01b031991821681179092556005805490911690556040517f53960c2e64e72b2c1326635f0c002d5cf63e7844d12ed107404693fedde43985905f90a2565b611297614927565b3330146112b75760405163887efaa560e01b815260040160405180910390fd5b60605f6112c76020880188614b8d565b6001600160a01b03168060015d506112e560e0880160c08901614b8d565b6002805c6001600160a01b0319166001600160a01b03831617905d5061130b6003611cf5565b87602001516001600160a01b031686888787604051602401611330949392919061570a565b60408051601f198184030181529190526020810180516001600160e01b03166001626c60f760e01b03191790526113688a6003612ca9565b60405160200161137992919061574c565b60408051601f198184030181529082905261139391615760565b5f604051808303815f865af19150503d805f81146113cc576040519150601f19603f3d011682016040523d82523d5f602084013e6113d1565b606091505b5092509050806113e357815160208301fd5b818060200190518101906113f7919061576b565b92506114036004611cf5565b6114108760400135612d33565b61142d57604051631217157160e31b815260040160405180910390fd5b61152a5a604089013561144360208b018b614b8d565b60208c015161145a6101408d016101208e01614b8d565b8b6114696101608f018f6157e7565b61147c5f5c60081c63ffffffff16612d70565b61149357604080515f8152602081019091526114c9565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050505b6040516024016114df9796959493929190615829565b60408051601f198184030181529190526020810180516001600160e01b0316630120c0d360e11b17905261151960e08c0160c08d01614b8d565b6001600160a01b0316929190612d78565b90508061154a57604051630357b89960e61b815260040160405180910390fd5b6115546005611cf5565b87602001516001600160a01b0316878686866040516024016115799493929190615884565b60408051601f198184030181529190526020810180516001600160e01b0316634667020160e11b1790526115ae8a6005612ca9565b6040516020016115bf92919061574c565b60408051601f19818403018152908290526115d991615760565b5f604051808303815f865af19150503d805f8114611612576040519150601f19603f3d011682016040523d82523d5f602084013e611617565b606091505b50925090508061162957815160208301fd5b8180602001905181019061163d919061576b565b92505f5f611649612d90565b92509250508161166c57604051638ac3609160e01b815260040160405180910390fd5b8015801561167f575061167d612daa565b155b1561169d57604051631d75534f60e01b815260040160405180910390fd5b896101200151156116c757845160405163304680d760e01b81526004810191909152602401610c16565b5050505095945050505050565b610f143382612dbd565b6116e6612219565b600454600580546001600160a01b0319166001600160a01b0384811691821790925560405191909216919082907ffc722bcd56a71612cd14b287fbf50545429e6c9e8de86ea7c3febdecd34882fd905f90a35050565b5f5f5f611747612d90565b925092509250909192565b61176482826080604060206003610ec5565b610efb85828686611f7a565b611778612219565b600380545f90915561178a3382611d08565b60405181815233907f87fa2ce024d3bdae31517696c13905fc0882bc1b4f4508060eb29358056de22b9060200160405180910390a250565b805f036117cc5750565b5f5c602881901c906001600160a01b03821633146117ff57816040516346ba7eb160e11b8152600401610c169190614ba8565b600460ff82161115611824576040516338961af360e21b815260040160405180910390fd5b5f61182d612d90565b509150508015611850576040516338961af360e21b815260040160405180910390fd5b61185984612d33565b1561186d576118683385611d08565b61188f565b60405163029d54f560e21b815247600482015260248101859052604401610c16565b50505050565b61189f3334612ee2565b565b5f5c60281c336001600160a01b038216146118d157806040516346ba7eb160e11b8152600401610c169190614ba8565b610f14612f90565b6118e1611fc9565b610f143382612fae565b6116d43334612ee2565b5f6004815c60ff161461191b576040516338961af360e21b815260040160405180910390fd5b336001600160a01b0360025c161461194657604051633006171960e21b815260040160405180910390fd5b5f5f5f611951612d90565b6001600160a01b0383165f9081526007602052604090205492955090935091506001600160701b031680861115611986578095505b5f61198f611ebd565b90505f61199e3460085c6150bd565b905034156119ad57808060085d505b6119b788826150bd565b8211156119ef57846119d9576001600160a01b038616600160a11b178060015d505b6119e381836156dc565b98975050505050505050565b83611a0a57600360a11b6001600160a01b038716178060015d505b505f979650505050505050565b5f8080805c602881901c90600881901c90611747565b604080516080810182525f8082526020820181905291810182905260608101829052611a6161012084016101008501614b8d565b6001600160a01b03166344912b6e846040518263ffffffff1660e01b8152600401611a8c91906158b9565b608060405180830381865afa158015611aa7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611acb91906158cb565b9050611af9611add6020850185614b8d565b611aef61012086016101008701614b8d565b8360200151612c50565b9150915091565b5f600a5b63ffffffff166001901b8263ffffffff16165f14159050919050565b5f5c15611b3f5760405162dc149f60e41b815260040160405180910390fd5b6020820151611b519082906001613130565b5050565b5f3a611b64836201d4c06150bd565b611b6e91906150d0565b90505f5f611b7a61315c565b9092509050611b898382613173565b8060045d50611b988383613196565b8060055d50348060085d505f8060065d505f8060075d505f8060035d505f8060015d505f6002805c6001600160a01b031916905d5050505050565b5f611bdd83615932565b90506001600160a01b037f000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b163303611cba57631b63f4db60e01b6001600160e01b0319821601611c4857825183015160405163e49c0b2560e01b815260048101829052602401610c16565b6001600160e01b03198116635933e62b60e11b1480611c7757506001600160e01b0319811663bdc56ad160e01b145b80611c9257506001600160e01b0319811663a695d44360e01b145b80611cad57506001600160e01b03198116635fd307e960e11b145b15611cba57805f5260045ffd5b6001600160e01b03198116634011dcb760e11b1480611ce35750611ce38263ffffffff16611b00565b15611cf057805f5260045ffd5b505050565b8060ff1660ff195f5c16175f81905d5050565b5f385f3884865af1611b515763b12d13eb5f526004601cfd5b5f5f5f611d2c612d90565b50909150506001600160a01b038416611d485785610160015193505b5f808060085c611d588a8a6131a5565b9850909550935091505f8080611d6e86886156dc565b905084841015611d8957611d8284866156dc565b9250611d96565b611d9385856156dc565b91505b8c60e001518015611dbe57508c61016001516001600160a01b0316886001600160a01b031614155b15611dd757611dcd81846150bd565b9250809950611e04565b8c61016001516001600160a01b0316886001600160a01b031603611dfd575f9950611e04565b5f99508a97505b81831115611e78578c60e00151611e3b57611e1f82846156dc565b6040516306de921b60e51b8152600401610c1691815260200190565b5f611e5289611e4a85876156dc565b84600161334d565b90508a811115611e6657611e1f8b826156dc565b611e70818c6156dc565b9a5050611e8c565b611e8c88611e8685856156dc565b8361363a565b611e966008611cf5565b8915611ea657611ea68b8b611d08565b5050505050505050935093915050565b5f80805d50565b5f60065c60055c611ed260045c60075c6150bd565b611edc91906150bd565b61121691906156dc565b5f5c602881901c90600881901c90336001600160a01b03841614611f1d57604051631e6d8cfb60e21b815260040160405180910390fd5b611f29338787856137c8565b611f46576040516343fcae1b60e01b815260040160405180910390fd5b8360ff168160ff166001901b165f03611f7257604051630106530b60e21b815260040160405180910390fd5b505050505050565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f51141716611fbc57637939f4245f526004601cfd5b5f60605260405250505050565b5f5c1561189f57604051630106530b60e21b815260040160405180910390fd5b5f611ff3826137f2565b6001600160a01b0384165f908152600760205260408120805492935091839183916120289084906001600160701b0316615970565b82546101009290920a6001600160701b03818102199093169183160217909155825463ffffffff60701b1916600160701b4363ffffffff1681029190911784556001600160a01b0387165f90815260066020526040902080548694509092600e926120989286929190041661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550836001600160a01b03167f7659747cd8571f1071eea946fdc648adcf181cad916f32a05f82c3a525976048847f00000000000000000000000000000000000000000000000000000000000000404361211491906150bd565b61211f9060016150bd565b604080519283526020830191909152015b60405180910390a250505050565b6121488282613829565b805f5f82825461215891906156dc565b90915550506040518181526001600160a01b038316907fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5906020015b60405180910390a25050565b5f5f6121ad8585856139b5565b90505f6121f9868686856040516024016121ca94939291906159ae565b60408051601f198184030181529190526020810180516001600160e01b031663d447616160e01b179052613a32565b90508080602001905181019061220f91906159dd565b9695505050505050565b6004546001600160a01b0316331461189f57604051633006171960e21b815260040160405180910390fd5b61224c6148c4565b5060408051610180810182529485526001600160a01b0395861660208601525f9085018190526060850181905260ff92909216608085015260a08401829052600160c085015260e084018290526101008401829052610120840191909152151561014083015290911661016082015290565b5f6002611b04565b606060016122d381611cf5565b5f5f86602001516001600160a01b0316856040516024016122f491906158b9565b60408051601f198184030181529190526020810180516001600160e01b0316630e75dff560e21b179052612329896001612ca9565b60405160200161233a92919061574c565b60408051601f198184030181529082905261235491615760565b5f604051808303815f865af19150503d805f811461238d576040519150601f19603f3d011682016040523d82523d5f602084013e612392565b606091505b509150915081156123e9576123b0866020015163ffffffff16613abd565b156123d257808060200190518101906123c991906159f8565b93505050612426565b5050604080515f8152602081019091529150612426565b8661014001511561240d57604051635933e62b60e11b815260040160405180910390fd5b604051635b47d49f60e11b815260040160405180910390fd5b509392505050565b6060600261243b81611cf5565b5f60605f619c4060405a61245090603f6150d0565b61245a9190615a8a565b61246491906156dc565b905080876060013510612477578061247d565b86606001355b905061248c8760400135612d33565b6124a957604051631217157160e31b815260040160405180910390fd5b88602001516001600160a01b031687604001358290896040516024016124cf91906158b9565b60408051601f198184030181529190526020810180516001600160e01b031663a395822560e01b1790526125048d6002612ca9565b60405160200161251592919061574c565b60408051601f198184030181529082905261252f91615760565b5f60405180830381858888f193505050503d805f811461256a576040519150601f19603f3d011682016040523d82523d5f602084013e61256f565b606091505b50909350915082156125bc5761258e886020015163ffffffff16613ac5565b156125b157818060200190518101906125a791906159f8565b94505050506125f9565b8594505050506125f9565b886101400151156125e05760405163bdc56ad160e01b815260040160405180910390fd5b604051639f885ee560e01b815260040160405180910390fd5b50949350505050565b5f6013611b04565b5f80835b8060ff16896060015160ff161015612695573686868b6060015160ff1681811061263a5761263a615aa9565b905060200281019061264c9190615abd565b90506126628a8a8a848561014001355f8b613acd565b92508960e00151156126795782935050505061220f565b506060890180519061268a82615adc565b60ff1690525061260e565b886101400151156126c657886040015162ffffff1660405163e49c0b2560e01b8152600401610c1691815260200190565b6126d9886020015163ffffffff16613d6d565b156126f757604051634011dcb760e11b815260040160405180910390fd5b505f98975050505050505050565b5f8280820361276e57876101400151156127345760405163e49c0b2560e01b81525f6004820152602401610c16565b612747876020015163ffffffff16613d6d565b1561276557604051634011dcb760e11b815260040160405180910390fd5b5f91505061220f565b60016101208901525f816001600160401b0381111561278f5761278f614bbc565b6040519080825280602002602001820160405280156127b8578160200160208202803683370190505b5090505f806127c86001856156dc565b90505f5a90505f5b8581101561285c576128088d8d8d8d8d868181106127f0576127f0615aa9565b90506020028101906128029190615abd565b8c613d75565b9350831580159061282057506001600160f01b038411155b15612854578061ffff16601085901b1785848151811061284257612842615aa9565b60209081029190910101525f19909201915b6001016127d0565b506128686001866156dc565b915061287384613fc1565b5f6101208d015261288d5a61288890836156dc565b614016565b815b60108582815181106128a3576128a3615aa9565b6020026020010151901c9350835f031561295d576128c181846156dc565b60ff1660608e015284515f9061ffff908790849081106128e3576128e3615aa9565b60200260200101511660ff1690506129248e8e8e8e8e8681811061290957612909615aa9565b905060200281019061291b9190615abd565b8960018f613acd565b94508d60e001511561293f578497505050505050505061220f565b815f0361294c575061295d565b5061295681615afa565b905061288f565b508b61014001511561298f578b6040015162ffffff1660405163e49c0b2560e01b8152600401610c1691815260200190565b6129a28b6020015163ffffffff16613d6d565b156129c057604051634011dcb760e11b815260040160405180910390fd5b505f9b9a5050505050505050505050565b60066129dc81611cf5565b5f5f86602001516001600160a01b031686604001518686604051602401612a0593929190615b0f565b60408051601f198184030181529190526020810180516001600160e01b0316630b65dadf60e11b179052612a3a896006612ca9565b604051602001612a4b92919061574c565b60408051601f1981840301815290829052612a6591615760565b5f604051808303815f865af19150503d805f8114612a9e576040519150601f19603f3d011682016040523d82523d5f602084013e612aa3565b606091505b50915091508115612ac55780806020019051810190612ac29190615b35565b91505b81158015612ae35750612ae1866020015163ffffffff1661404a565b155b15612b245786610140015115612b0c5760405163a695d44360e01b815260040160405180910390fd5b60405162d14f5160e11b815260040160405180910390fd5b5015156101009095019490945250505050565b5f6008611b04565b6007612b4a81611cf5565b5f84602001516001600160a01b03168484604051602401612b6c929190615b50565b60408051601f198184030181529190526020810180516001600160e01b031663b1d5b5a360e01b179052612ba1876007612ca9565b604051602001612bb292919061574c565b60408051601f1981840301815290829052612bcc91615760565b5f604051808303815f865af19150503d805f8114612c05576040519150601f19603f3d011682016040523d82523d5f602084013e612c0a565b606091505b5050905080610efb5784610140015115612c3757604051635fd307e960e11b815260040160405180910390fd5b6040516333c0622b60e11b815260040160405180910390fd5b5f5f612c5d8585856139b5565b90505f6121f986868685604051602401612c7a94939291906159ae565b60408051601f198184030181529190526020810180516001600160e01b0316630cfce7b160e11b179052613a32565b6060816008811115612cbd57612cbd61550b565b60ff1660c084015261016083015160e084015161010085015160608601516080870151866008811115612cf257612cf261550b565b6040808a01516101208b01516101408c01519251612d1c9998979695949390600190602001615b7b565b604051602081830303815290604052905092915050565b5f815f03612d4357506001919050565b81471015612d5257505f919050565b8160075f612d6183835c6150bd565b92505081905d50600192915050565b5f600f611b04565b5f5f5f5f845160208601878a8af19695505050505050565b60015c90600160a11b8216151590600160a21b8316151590565b5f612db3611ebd565b60085c1015905090565b5f612dc7826137f2565b6001600160a01b0384165f90815260066020526040812080549293508392909190612dfc9084906001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550815f5f828254612e3091906156dc565b90915550506001600160a01b0383165f9081526007602052604081208054839290612e659084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b031602179055508160015f828254612e9a91906150bd565b90915550506040518281526001600160a01b038416907f6b1d99469ed62a423d7e402bfa68a467261ca2229127c55045ee41e5d9a0f21d9060200160405180910390a2505050565b805f5f828254612ef291906150bd565b90915550612f019050816137f2565b6001600160a01b0383165f9081526006602052604081208054909190612f319084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550816001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858260405161219491815260200190565b341561189f573460085f612fa583835c6150bd565b92505081905d50565b6001600160a01b0382165f90815260076020526040902054612ffe907f000000000000000000000000000000000000000000000000000000000000004090600160701b900463ffffffff166150bd565b431161301d5760405163078e135760e51b815260040160405180910390fd5b5f613027826137f2565b6001600160a01b0384165f90815260066020526040902080549192509082908290600e90613066908490600160701b90046001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b031602179055508260015f82825461309b91906156dc565b90915550508054829082905f906130bc9084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550825f5f8282546130f091906150bd565b90915550506040518381526001600160a01b038516907f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a690602001612130565b600160281b600160c81b03602884901b1664ffffffff00600884901b161760ff821617805f5d50505050565b600254608081901c916001600160801b0390911690565b5f6298968061318283826150bd565b61318c90856150d0565b6110669190615a8a565b5f6298968061318c83856150d0565b60035460075c9060045c9060065c905f9060055c82806131c361315c565b915091505f5a90505f6131d63a836150d0565b90506131e28184613173565b6131ec908a6156dc565b98508b60e001511561322c576132028185613196565b61320c90866156dc565b9650613218878b6150bd565b995061322487876150bd565b6003556132b6565b60035c80156132aa5761324b8561324386826150bd565b839190614052565b97505f61325889836156dc565b90505f61326d6132688d88614068565b614083565b90508082111561328e5761328181836156dc565b61328b908b6150bd565b99505b6132988a8e6150bd565b9c506132a48a8a6150bd565b60035550505b50505050505050613344565b60808c015160ff161561333d575f6132ce8a85614068565b90505f6207a1208e606001518f608001516132e99190615c1c565b6132f69060ff168f6150d0565b61330091906150bd565b90508084111561333a575f8461331683856150d0565b6133209190615a8a565b61332a90846156dc565b9050613336818c6150bd565b9a50505b50505b5050505050505b92959194509250565b5f5f613358856137f2565b6001600160a01b0387165f90815260076020908152604091829020825160a08101845290546001600160701b0380821680845263ffffffff600160701b8404169484019490945262ffffff600160901b8304811695840195909552600160a81b820490941660608301526001600160401b03600160c01b909104166080820152929350908316111561350f576001600160a01b0387165f9081526006602090815260408083208151808301909252546001600160701b038082168352600160701b9091048116928201839052845191939261343692909116906150bd565b905080846001600160701b031611156134a95761345381896156dc565b6001600160a01b038a165f90815260066020819052604082208054600160701b600160e01b031916905581865291965086919061349183835c6150bd565b92505081905d506134a285896156dc565b9750613508565b6134c46134bf6001600160701b038616836156dc565b6137f2565b6001600160a01b038a165f90815260066020526040812080546001600160701b0393909316600160701b02600160701b600160e01b03199093169290921790915583525b505061352d565b81815f018181516135209190615970565b6001600160701b03169052505b6135428185801561353c575084155b876140a5565b63ffffffff43811660208084019182526001600160a01b038a165f9081526007909152604080822085518154945192870151606088015160808901516001600160401b0316600160c01b026001600160c01b0362ffffff928316600160a81b0262ffffff60a81b1993909416600160901b029290921665ffffffffffff60901b1996909916600160701b026001600160901b03199098166001600160701b03909416939093179690961793909316959095179190911792909216929092179055600180548892906136149084906156dc565b9091555086905060085f61362983835c6150bd565b92505081905d505050949350505050565b6001600160a01b0383165f90815260076020908152604091829020825160a08101845290546001600160701b0381168252600160901b810462ffffff90811694830194909452600160a81b81049093166060820152600160c01b9092046001600160401b0316608083015263ffffffff4316908201526136b9836137f2565b815182906136c890839061598f565b6001600160701b0316905250600180548491905f906136e89084906150bd565b909155506136fa9050816001846140a5565b6001600160a01b0384165f908152600760208181526040808420855181549387015192870151606088015160808901516001600160701b039093166001600160901b031990961695909517600160701b63ffffffff909516949094029390931765ffffffffffff60901b1916600160901b62ffffff9485160262ffffff60a81b191617600160a81b9390941692909202929092176001600160c01b0316600160c01b6001600160401b039092169190910217905584916137bb83835c6150bd565b92505081905d5050505050565b5f6137d48484846121a0565b6001600160a01b0316856001600160a01b0316149050949350505050565b5f6001600160701b03821115613825576040516306dfcc6560e41b81526070600482015260248101839052604401610c16565b5090565b5f613833826137f2565b6001600160a01b0384165f9081526006602052604090208054919250906001600160701b03908116908316811061388e5761386e8382615970565b82546001600160701b0319166001600160701b0391909116178255610efb565b6001600160a01b0385165f908152600760205260409020546138de907f000000000000000000000000000000000000000000000000000000000000004090600160701b900463ffffffff166150bd565b43111561398a575f6138f08285615970565b83546001600160701b03191680855590915081908490600e90613924908490600160701b90046001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505f816001600160701b03169050805f5f82825461396591906150bd565b925050819055508060015f82825461397d91906156dc565b90915550610efb92505050565b6040516307d2457d60e21b81526001600160701b038216600482015260248101859052604401610c16565b604080517f0e32c5b0f13b9c1504ccd7b3abad5a1c4549dccb88862cb7b52c51276e8ab74b602080830191909152606095861b6001600160601b0319908116838501529490951b909316605484015260e09190911b6001600160e01b03191660688301528051604c818403018152606c9092019052805191012090565b60605f5f7f000000000000000000000000a70aaf5dd6b3b7f06617780c964f2638f24394bf6001600160a01b031684604051613a6e9190615760565b5f60405180830381855af49150503d805f8114613aa6576040519150601f19603f3d011682016040523d82523d5f602084013e613aab565b606091505b50915091508161106657805160208201fd5b5f6003611b04565b5f6004611b04565b5f5f5a90505f84613bae577f000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e96001600160a01b0316639f7e72b6888c5f01518b608001358e6101600151613b2a8f6020015163ffffffff16614109565b6040518663ffffffff1660e01b8152600401613b4a959493929190615c35565b602060405180830381865afa158015613b65573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b899190615092565b9050613bab613ba061014089016101208a01614b8d565b8a6040015183614111565b90505b80613cb3575f613bc08a89858561413d565b9092509050613bcf888b614246565b82179150613be08a878b8b866142d8565b915081613cb157613bef614927565b613bfc8c8a8a858a61431a565b909350905082613caf578a516001600160a01b0316613c1e60208b018b614b8d565b6001600160a01b0316613c3760e08c0160c08d01614b8d565b6001600160a01b03167f94e79da376f3bc5202c947c2466a329832d3e9af2f4e094a18c160868453273c613c736101408e016101208f01614b8d565b8c6001808a604051613c89959493929190615c76565b60405180910390a4600160e08d015262ffffff90921660408c015250519150613d629050565b505b505b62ffffff811660408b0152613ccb8783838815614550565b88516001600160a01b0316613ce36020890189614b8d565b6001600160a01b0316613cfc60e08a0160c08b01614b8d565b6001600160a01b03167f94e79da376f3bc5202c947c2466a329832d3e9af2f4e094a18c160868453273c613d386101408c016101208d01614b8d565b8a62fe0000871615155f88604051613d54959493929190615c76565b60405180910390a45f925050505b979650505050505050565b5f6010611b04565b5f5f5a90505f5f7f000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e96001600160a01b0316639f7e72b6878b5f01518a608001358d6101600151613dce8e6020015163ffffffff16614109565b6040518663ffffffff1660e01b8152600401613dee959493929190615c35565b602060405180830381865afa158015613e09573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e2d9190615092565b9050613e4f613e4461014088016101208901614b8d565b896040015183614111565b9050613e5d8887858461413d565b92509050613e6b8689614246565b178015613e7d575f9350505050610e81565b613e90886020015163ffffffff16614109565b15613eae57613e9f8787614640565b613eae575f9350505050610e81565b5f5f306001600160a01b031684306001600160a01b031663966a1f9a8e8c8d61014001358d604051602401613ee69493929190615ca6565b60408051601f198184030181529181526020820180516001600160e01b031660e09490941b939093179092529051613f1e9250615760565b5f604051808303815f8787f1925050503d805f8114613f58576040519150601f19603f3d011682016040523d82523d5f602084013e613f5d565b606091505b50915091508115613f815760405163039f249b60e61b815260040160405180910390fd5b63304680d760e01b613f9282615932565b6001600160e01b03191603613fb157805101519450610e819350505050565b505f9a9950505050505050505050565b80515f82528060051b8201601f19602084015b60200182811161400f5780518282018051828111613ff457505050613fd4565b5b602082015283018051828111613ff5575060200152613fd4565b5050509052565b5f5f61402061315c565b9092509050614030838383614756565b60065f61403e83835c6150bd565b92505081905d50505050565b5f6014611b04565b5f8161405e84866150d0565b61120e9190615a8a565b5f61407682629896806150bd565b61318c62989680856150d0565b5f62989680614095627a1200846150d0565b61409f9190615a8a565b92915050565b81156140c05760408301805160010162ffffff1690526140d1565b60608301805160010162ffffff1690525b6140e76140e2633b9aca0083615a8a565b61477a565b836080018181516140f89190615ce2565b6001600160401b0316905250505050565b5f6011611b04565b5f826001600160a01b0316846001600160a01b03161461413657506108008117611066565b5092915050565b5f5f856060015163ffffffff166207a12061415891906150bd565b84101561416e576020929092179182915061423d565b6201e84861418a8660600135886060015163ffffffff166147af565b61419491906150bd565b90505f6141af6141a86101608801886157e7565b90506147d5565b6141b9833a6150d0565b6141c391906150bd565b905047866040013511156141e25750618000929092179182915061423d565b6141ef6201e848836156dc565b91505f60078161420260208a018a614b8d565b6001600160a01b0316815260208101919091526040015f20546001600160701b03169050808211156142375761200094909417935b84935050505b94509492505050565b5f60a08301351580159061425d57508260a0013543115b1561428d57614275826020015163ffffffff16614109565b614280576008614283565b60025b6001901b1761409f565b5f60078161429e6020870187614b8d565b6001600160a01b0316815260208101919091526040015f2054600160701b900463ffffffff16905043811061413657506110001792915050565b5f6142ec866020015163ffffffff16614109565b80156142f6575084155b801561430957506143078484614640565b155b156125f95750608017949350505050565b5f614323614927565b5f5f306001600160a01b031686306001600160a01b031663966a1f9a8c8c8c8b6040516024016143569493929190615ca6565b60408051601f198184030181529181526020820180516001600160e01b031660e09490941b93909317909252905161438e9250615760565b5f604051808303815f8787f1925050503d805f81146143c8576040519150601f19603f3d011682016040523d82523d5f602084013e6143cd565b606091505b509150915081156143f357808060200190518101906143ec919061576b565b9250614544565b5f6143fd82615932565b90506353068ee960e11b6001600160e01b03198216016144255760065b6001901b9450614542565b630de8ea8f60e31b6001600160e01b031982160161444457600d61441a565b6317f387a160e21b6001600160e01b031982160161446357601061441a565b62a8476760e61b6001600160e01b031982160161448157601161441a565b633277ac1760e21b6001600160e01b03198216016144a057601261441a565b6305bb473560e21b6001600160e01b03198216016144bf57601361441a565b6350dbf98960e01b6001600160e01b03198216016144de57600a61441a565b63e28aacb160e01b6001600160e01b03198216016144fd57601561441a565b63753c9f6f60e01b6001600160e01b031982160161451c57601661441a565b637781055b60e01b6001600160e01b031982160161453b57600661441a565b6280000094505b505b50509550959350505050565b5f3a5a61455f611388876150bd565b61456991906156dc565b61457391906150d0565b90505f5f61457f61315c565b9150915083156145a75761459a6141a86101608901896157e7565b6145a490846150bd565b92505b60ff8516156145d5576145bb838383614756565b60065f6145c983835c6150bd565b92505081905d50614637565b5f6145e1848484614756565b90505f6145ee85836156dc565b90505f61460961460160208c018c614b8d565b84855f61334d565b9050808211156146335761461d81836156dc565b60035f61462b83835c6150bd565b92505081905d505b5050505b50505050505050565b5f614652610100830160e08401614b8d565b6001600160a01b031661466d61012085016101008601614b8d565b6001600160a01b03161461468257505f61409f565b60c08301351580614695575060a0820135155b806146a757508260c001358260a00135145b6146b257505f61409f565b5f6101008301356146c66020850185614b8d565b8460a001356040516020016146fb9392919092835260609190911b6001600160601b0319166020830152603482015260540190565b60408051601f1981840301815291815281516020928301205f818152600890935291205490915060ff1615614733575f91505061409f565b5f908152600860205260409020805460ff19166001908117909155905092915050565b5f629896808261476685836150bd565b61477091906150bd565b61405e90866150d0565b5f6001600160401b0382111561382557604080516306dfcc6560e41b8152600481019190915260248101839052604401610c16565b5f6147c06207a120629896806150bd565b629896808385106131825761318c90846150d0565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614827573a6008614813610260856150bd565b61481d91906150d0565b61409f91906150d0565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016632c652d89614862610260856150bd565b6040518263ffffffff1660e01b815260040161488091815260200190565b602060405180830381865afa15801561489b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061409f9190615092565b919050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040518060a001604052805f81526020015f81526020015f81526020015f151581526020015f151581525090565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6110666020830184614955565b5f6101a082840312156149a6575f5ffd5b50919050565b5f5f83601f8401126149bc575f5ffd5b5081356001600160401b038111156149d2575f5ffd5b6020830191508360208260051b85010111156149ec575f5ffd5b9250929050565b6001600160a01b0381168114610f14575f5ffd5b80356148bf816149f3565b5f5f5f5f5f60808688031215614a26575f5ffd5b85356001600160401b03811115614a3b575f5ffd5b614a4788828901614995565b95505060208601356001600160401b03811115614a62575f5ffd5b614a6e888289016149ac565b90955093505060408601356001600160401b03811115614a8c575f5ffd5b86016101208189031215614a9e575f5ffd5b91506060860135614aae816149f3565b809150509295509295909350565b5f5f5f5f5f60a08688031215614ad0575f5ffd5b8535614adb816149f3565b94506020860135614aeb816149f3565b9350604086013592506060860135614b02816149f3565b91506080860135614aae816149f3565b5f60208284031215614b22575f5ffd5b5035919050565b5f5f60408385031215614b3a575f5ffd5b8235614b45816149f3565b91506020830135614b55816149f3565b809150509250929050565b6001600160a01b03169052565b5f5f60408385031215614b7e575f5ffd5b50508035926020909101359150565b5f60208284031215614b9d575f5ffd5b8135611066816149f3565b6001600160a01b0391909116815260200190565b634e487b7160e01b5f52604160045260245ffd5b604051608081016001600160401b0381118282101715614bf257614bf2614bbc565b60405290565b60405161018081016001600160401b0381118282101715614bf257614bf2614bbc565b604051601f8201601f191681016001600160401b0381118282101715614c4357614c43614bbc565b604052919050565b63ffffffff81168114610f14575f5ffd5b80356148bf81614c4b565b8015158114610f14575f5ffd5b80356148bf81614c67565b5f5f5f5f5f5f5f5f888a03610140811215614c98575f5ffd5b6080811215614ca5575f5ffd5b50614cae614bd0565b8935614cb9816149f3565b815260208a0135614cc981614c4b565b602082015260408a0135614cdc816149f3565b604082015260608a0135614cef81614c4b565b6060820152975060808901356001600160401b03811115614d0e575f5ffd5b614d1a8b828c01614995565b97505060a08901356001600160401b03811115614d35575f5ffd5b614d418b828c016149ac565b9097509550614d54905060c08a01614a07565b9350614d6260e08a01614a07565b92506101008901359150614d796101208a01614c74565b90509295985092959890939650565b805182526020810151614d9e6020840182614b60565b506040810151614db5604084018262ffffff169052565b506060810151614dca606084018260ff169052565b506080810151614ddf608084018260ff169052565b5060a0810151614df460a084018260ff169052565b5060c0810151614e0960c084018260ff169052565b5060e0810151614e1d60e084018215159052565b50610100810151614e3361010084018215159052565b50610120810151614e4961012084018215159052565b50610140810151614e5f61014084018215159052565b50610160810151611cf0610160840182614b60565b610180810161409f8284614d88565b62ffffff81168114610f14575f5ffd5b80356148bf81614e83565b60ff81168114610f14575f5ffd5b80356148bf81614e9e565b5f5f83601f840112614ec7575f5ffd5b5081356001600160401b03811115614edd575f5ffd5b6020830191508360208285010111156149ec575f5ffd5b5f5f5f5f5f8587036101e0811215614f0a575f5ffd5b610180811215614f18575f5ffd5b50614f21614bf8565b86358152614f3160208801614a07565b6020820152614f4260408801614e93565b6040820152614f5360608801614eac565b6060820152614f6460808801614eac565b6080820152614f7560a08801614eac565b60a0820152614f8660c08801614eac565b60c0820152614f9760e08801614c74565b60e0820152614fa96101008801614c74565b610100820152614fbc6101208801614c74565b610120820152614fcf6101408801614c74565b610140820152614fe26101608801614a07565b61016082015294506101808601356001600160401b03811115615003575f5ffd5b61500f88828901614995565b9450506101a086013592506101c08601356001600160401b03811115615033575f5ffd5b61503f88828901614eb7565b969995985093965092949392505050565b8051825260208101516020830152604081015160408301526060810151151560608301526080810151151560808301525050565b60a0810161409f8284615050565b5f602082840312156150a2575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561409f5761409f6150a9565b808202811582820484141761409f5761409f6150a9565b60018060a01b03815116825263ffffffff602082015116602083015260018060a01b03604082015116604083015263ffffffff60608201511660608301525050565b5f5f8335601e1984360301811261513e575f5ffd5b83016020810192503590506001600160401b0381111561515c575f5ffd5b8036038213156149ec575f5ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6151a48261519f83614a07565b614b60565b5f6151b160208301614a07565b6151be6020850182614b60565b5060408281013590840152606080830135908401526080808301359084015260a0808301359084015260c080830135908401526151fd60e08301614a07565b61520a60e0850182614b60565b506152186101008301614a07565b615226610100850182614b60565b506152346101208301614c5c565b63ffffffff1661012084015261524d6101408301614a07565b61525b610140850182614b60565b5061526a610160830183615129565b6101a06101608601526152826101a08601828461516a565b915050615293610180840184615129565b85830361018087015261220f83828461516a565b6152b48261519f83614a07565b5f6152c160208301614a07565b6152ce6020850182614b60565b5060408281013590840152606080830135908401526080808301359084015260a0808301359084015261530360c08301614a07565b61531060c0850182614b60565b5061531d60e08301614a07565b61532a60e0850182614b60565b5061010082810135908401526153436101208301614a07565b615351610120850182614b60565b50610140828101359084015261526a610160830183615129565b5f8383855260208501945060208460051b820101835f5b868110156153cb57838303601f1901885281353687900361019e190181126153a8575f5ffd5b6153b4848883016152a7565b6020998a0199909450929092019150600101615382565b50909695505050505050565b6153e1818a6150e7565b61014060808201525f6153f861014083018a615192565b82810360a084015261540b81898b61536b565b905082810360c08401526154228161519f89614a07565b61542e60208801614a07565b61543b6020830182614b60565b50604087810135908201526060808801359082015261545c60808801614a07565b6154696080830182614b60565b5061547660a08801614a07565b61548360a0830182614b60565b5060c0878101359082015260e080880135908201526154a6610100880188615129565b6101206101008401526154be6101208401828461516a565b93505050508460e08301526154d7610100830185614b60565b8215156101208301529998505050505050505050565b5f602082840312156154fd575f5ffd5b8151601e8110611066575f5ffd5b634e487b7160e01b5f52602160045260245ffd5b60208101601e831061553f57634e487b7160e01b5f52602160045260245ffd5b91905290565b60ff818116838216019081111561409f5761409f6150a9565b615568818a6150e7565b61014060808201525f61557f61014083018a615192565b82810360a084015261559281898b61536b565b6001600160a01b0397881660c08501529590961660e08301525061010081019290925215156101209091015295945050505050565b80516148bf816149f3565b80516148bf81614e83565b80516148bf81614e9e565b80516148bf81614c67565b5f610180828403128015615605575f5ffd5b5061560e614bf8565b8251815261561e602084016155c7565b602082015261562f604084016155d2565b6040820152615640606084016155dd565b6060820152615651608084016155dd565b608082015261566260a084016155dd565b60a082015261567360c084016155dd565b60c082015261568460e084016155e8565b60e082015261569661010084016155e8565b6101008201526156a961012084016155e8565b6101208201526156bc61014084016155e8565b6101408201526156cf61016084016155c7565b6101608201529392505050565b8181038181111561409f5761409f6150a9565b5f602082840312156156ff575f5ffd5b815161106681614c4b565b848152606060208201525f61572260608301866152a7565b8281036040840152613d6281858761516a565b5f81518060208401855e5f93019283525090919050565b5f61120e61575a8386615735565b84615735565b5f6110668284615735565b5f60a082840312801561577c575f5ffd5b5060405160a081016001600160401b038111828210171561579f5761579f614bbc565b60409081528351825260208085015190830152838101519082015260608301516157c881614c67565b606082015260808301516157db81614c67565b60808201529392505050565b5f5f8335601e198436030181126157fc575f5ffd5b8301803591506001600160401b03821115615815575f5ffd5b6020019150368190038213156149ec575f5ffd5b6001600160a01b0388811682528781166020830152861660408201526060810185905260c0608082018190525f90615864908301858761516a565b82810360a08401526158768185614955565b9a9950505050505050505050565b60e081525f61589660e08301876152a7565b82810360208401526158a981868861516a565b915050610e816040830184615050565b602081525f6110666020830184615192565b5f60808284031280156158dc575f5ffd5b506158e5614bd0565b82516158f0816149f3565b8152602083015161590081614c4b565b60208201526040830151615913816149f3565b6040820152606083015161592681614c4b565b60608201529392505050565b805160208201516001600160e01b0319811691906004821015615969576001600160e01b0319600483900360031b81901b82161692505b5050919050565b6001600160701b03828116828216039081111561409f5761409f6150a9565b6001600160701b03818116838216019081111561409f5761409f6150a9565b6001600160a01b03948516815292909316602083015263ffffffff166040820152606081019190915260800190565b5f602082840312156159ed575f5ffd5b8151611066816149f3565b5f60208284031215615a08575f5ffd5b81516001600160401b03811115615a1d575f5ffd5b8201601f81018413615a2d575f5ffd5b80516001600160401b03811115615a4657615a46614bbc565b615a59601f8201601f1916602001614c1b565b818152856020838501011115615a6d575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f82615aa457634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b5f823561019e19833603018112615ad2575f5ffd5b9190910192915050565b5f60ff821660ff8103615af157615af16150a9565b60010192915050565b5f81615b0857615b086150a9565b505f190190565b60018060a01b0384168152826020820152606060408201525f610e816060830184614955565b5f60208284031215615b45575f5ffd5b815161106681614c67565b8215158152604060208201525f61120e6040830184614955565b60f81b6001600160f81b0319169052565b60608b901b6001600160601b031916815289151560f890811b6014830152891515811b601583015288901b6001600160f81b0319166016820152615bc26017820188615b6a565b615bcf6018820187615b6a565b615be8601982018660e81b6001600160e81b0319169052565b83151560f81b601c82015282151560f81b601d820152615c0b601e820183615b6a565b601f019a9950505050505050505050565b60ff828116828216039081111561409f5761409f6150a9565b60a081525f615c4760a08301886152a7565b60208301969096525060408101939093526001600160a01b039190911660608301521515608090910152919050565b6001600160a01b039590951685526020850193909352901515604084015215156060830152608082015260a00190565b615cb08186614d88565b6101e06101808201525f615cc86101e08301866152a7565b846101a08401528281036101c0840152613d628185614955565b6001600160401b03818116838216019081111561409f5761409f6150a956fea164736f6c634300081c000a

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

0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000001e8480000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e9000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b00000000000000000000000078c5d8df575098a97a3bd1f8dcceb22d71f3a4740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a70aaf5dd6b3b7f06617780c964f2638f24394bf

-----Decoded View---------------
Arg [0] : escrowDuration (uint256): 64
Arg [1] : atlasSurchargeRate (uint256): 500000
Arg [2] : bundlerSurchargeRate (uint256): 2000000
Arg [3] : verification (address): 0xf31cf8740Dc4438Bb89a56Ee2234Ba9d5595c0E9
Arg [4] : simulator (address): 0x702b0b3690642B880dF6B018ead7F3C30ECe5c6b
Arg [5] : initialSurchargeRecipient (address): 0x78C5d8DF575098a97A3bD1f8DCCEb22D71F3a474
Arg [6] : l2GasCalculator (address): 0x0000000000000000000000000000000000000000
Arg [7] : factoryLib (address): 0xA70aAf5dD6B3B7F06617780c964f2638f24394BF

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [1] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [2] : 00000000000000000000000000000000000000000000000000000000001e8480
Arg [3] : 000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e9
Arg [4] : 000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b
Arg [5] : 00000000000000000000000078c5d8df575098a97a3bd1f8dcceb22d71f3a474
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 000000000000000000000000a70aaf5dd6b3b7f06617780c964f2638f24394bf


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  ]
[ 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.