APE Price: $1.55 (+12.28%)

Contract

0x55E0007700c92c095078000b0000B1000000804E

Overview

APE Balance

Apechain LogoApechain LogoApechain Logo0.00000000099990257 APE

APE Value

Less Than $0.01 (@ $1.55/APE)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Create Tournamen...65316962024-12-11 15:07:481 hr ago1733929668IN
0x55E00077...00000804E
0 APE0.0068812225.42069
Liquidate65308622024-12-11 14:48:251 hr ago1733928505IN
0x55E00077...00000804E
0 APE0.0055920925.42069
Trade65308482024-12-11 14:47:581 hr ago1733928478IN
0x55E00077...00000804E
0 APE0.0073544325.42069
Trade65308302024-12-11 14:47:211 hr ago1733928441IN
0x55E00077...00000804E
0 APE0.0067390725.42069
Trade65308052024-12-11 14:47:041 hr ago1733928424IN
0x55E00077...00000804E
0 APE0.0073358725.42069
Trade65307882024-12-11 14:46:351 hr ago1733928395IN
0x55E00077...00000804E
0 APE0.0067381625.42069
Trade65307682024-12-11 14:46:071 hr ago1733928367IN
0x55E00077...00000804E
0 APE0.0073317325.42069
Trade65307642024-12-11 14:45:531 hr ago1733928353IN
0x55E00077...00000804E
0 APE0.0067387725.42069
Trade65307382024-12-11 14:45:061 hr ago1733928306IN
0x55E00077...00000804E
0 APE0.0073246925.42069
Trade65307292024-12-11 14:44:501 hr ago1733928290IN
0x55E00077...00000804E
0 APE0.0067376225.42069
Trade65307042024-12-11 14:44:041 hr ago1733928244IN
0x55E00077...00000804E
0 APE0.0076999725.42069
Enter Tournament65306752024-12-11 14:43:201 hr ago1733928200IN
0x55E00077...00000804E
10 APE0.0107890225.42069
Create Tournamen...65292102024-12-11 14:02:402 hrs ago1733925760IN
0x55E00077...00000804E
0 APE0.006881225.42069
Trade65284932024-12-11 13:40:192 hrs ago1733924419IN
0x55E00077...00000804E
0 APE0.0067307825.42069
Trade65284752024-12-11 13:39:412 hrs ago1733924381IN
0x55E00077...00000804E
0 APE0.0014047225.42069
Trade65284742024-12-11 13:39:392 hrs ago1733924379IN
0x55E00077...00000804E
0 APE0.0072760825.42069
Create Tournamen...65272882024-12-11 12:57:313 hrs ago1733921851IN
0x55E00077...00000804E
0 APE0.006881225.42069
Create Tournamen...65258612024-12-11 11:52:224 hrs ago1733917942IN
0x55E00077...00000804E
0 APE0.006881225.42069
Trade65241702024-12-11 10:49:535 hrs ago1733914193IN
0x55E00077...00000804E
0 APE0.0067389925.42069
Create Tournamen...65240622024-12-11 10:47:335 hrs ago1733914053IN
0x55E00077...00000804E
0 APE0.006881225.42069
Trade65234862024-12-11 10:25:365 hrs ago1733912736IN
0x55E00077...00000804E
0 APE0.0072668825.42069
Trade65227742024-12-11 9:57:206 hrs ago1733911040IN
0x55E00077...00000804E
0 APE0.0067288825.42069
Trade65227622024-12-11 9:56:466 hrs ago1733911006IN
0x55E00077...00000804E
0 APE0.0014019225.42069
Trade65227612024-12-11 9:56:436 hrs ago1733911003IN
0x55E00077...00000804E
0 APE0.0072751425.42069
Create Tournamen...65224422024-12-11 9:42:236 hrs ago1733910143IN
0x55E00077...00000804E
0 APE0.006881225.42069
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
65308622024-12-11 14:48:251 hr ago1733928505
0x55E00077...00000804E
1 wei
65308612024-12-11 14:48:221 hr ago1733928502
0x55E00077...00000804E
1 wei
65308482024-12-11 14:47:581 hr ago1733928478
0x55E00077...00000804E
1 wei
65308302024-12-11 14:47:211 hr ago1733928441
0x55E00077...00000804E
1 wei
65308052024-12-11 14:47:041 hr ago1733928424
0x55E00077...00000804E
1 wei
65307882024-12-11 14:46:351 hr ago1733928395
0x55E00077...00000804E
1 wei
65307682024-12-11 14:46:071 hr ago1733928367
0x55E00077...00000804E
1 wei
65307642024-12-11 14:45:531 hr ago1733928353
0x55E00077...00000804E
1 wei
65307382024-12-11 14:45:061 hr ago1733928306
0x55E00077...00000804E
1 wei
65307292024-12-11 14:44:501 hr ago1733928290
0x55E00077...00000804E
1 wei
65307042024-12-11 14:44:041 hr ago1733928244
0x55E00077...00000804E
1 wei
65306752024-12-11 14:43:201 hr ago1733928200
0x55E00077...00000804E
10 APE
65303222024-12-11 14:33:401 hr ago1733927620
0x55E00077...00000804E
1 wei
65302962024-12-11 14:33:031 hr ago1733927583
0x55E00077...00000804E
1 wei
65302502024-12-11 14:31:421 hr ago1733927502
0x55E00077...00000804E
1 wei
65302282024-12-11 14:30:571 hr ago1733927457
0x55E00077...00000804E
1 wei
65302042024-12-11 14:30:291 hr ago1733927429
0x55E00077...00000804E
1 wei
65301792024-12-11 14:29:521 hr ago1733927392
0x55E00077...00000804E
1 wei
65301512024-12-11 14:29:101 hr ago1733927350
0x55E00077...00000804E
1 wei
65301242024-12-11 14:28:471 hr ago1733927327
0x55E00077...00000804E
1 wei
65300922024-12-11 14:28:151 hr ago1733927295
0x55E00077...00000804E
1 wei
65300642024-12-11 14:27:441 hr ago1733927264
0x55E00077...00000804E
1 wei
65284932024-12-11 13:40:192 hrs ago1733924419
0x55E00077...00000804E
1 wei
65284742024-12-11 13:39:392 hrs ago1733924379
0x55E00077...00000804E
1 wei
65241702024-12-11 10:49:535 hrs ago1733914193
0x55E00077...00000804E
1 wei
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TopTrader

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion, Unlicense license
File 1 of 9 : TopTrader.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import {IPyth} from "pyth-sdk-solidity/IPyth.sol";
import {PythStructs} from "pyth-sdk-solidity/PythStructs.sol";
import {OwnableRoles} from "solady/auth/OwnableRoles.sol";
import {SignatureCheckerLib} from "solady/utils/SignatureCheckerLib.sol";
import {IRebootTournament} from "./interfaces/IRebootTournament.sol";
import {Direction, Trade, InternalPrice, TournamentConfig} from "./structs/TopTraderStructs.sol";

/**
 * * * * * * * * * * * * * * * * * * * * * * * * *
 * _______  _____   _____                           *
 *    |    |     | |_____]                          *
 *    |    |_____| |                                *
 *                                                  *
 * _______  ______ _______ ______  _______  ______  *
 *    |    |_____/ |_____| |     \ |______ |_____/  *
 *    |    |    \_ |     | |_____/ |______ |    \_  *
 * * * * * * * * * * * * * * * * * * * * * * * * * *
 */
contract TopTrader is OwnableRoles {
    // The price is older than the valid time period.
    error StalePrice();

    // block.timestamp is not within the tournament's start and end time.
    error NotActive();

    // The pair does not match the current active trade.
    error MismatchedPairs();

    // A transfer has reverted.
    error TransferFailed();

    // The amount is 0.
    error InvalidAmount();

    // The user has already entered the tournament.
    error AlreadyEntered();

    // Must provide entry fee in the form of msg.value.
    error InsufficientEntryFee();

    // Prices cannot be finalized while the tournament is active.
    error TournamentActive();

    // The user does not have enough balance to execute the trade.
    error InsufficientBalance(int256 balanceInBips, int256 requiredAmountInBips);

    // The minimum hold duration has not been met.
    error MinimumHoldDurationNotMet();

    // The slippage scaling factor is too high.
    error SlippageTooHigh();

    // The liquidation bounty is too high.
    error LiquidationBountyTooHigh();

    // An address is initialized to the zero address.
    error ZeroAddress();

    // The minimum timestamp has not been met.
    error MinTimestampNotMet();

    // The signature is invalid.
    error InvalidSignature();

    // The nonce has already been used.
    error NonceAlreadyUsed();

    // The caller is not the counterparty signer or the trader.
    error InvalidCaller();

    // The signature has expired.
    error SignatureExpired();

    // Trade function allows price updates of length 1 only.
    error InvalidPriceUpdates();

    // The length of the pairs and prices arrays do not match.
    error ArrayLengthMismatch();

    // The price update publish time is in the future.
    error InvalidTimestamp();

    // Emitted when a new tournament is created.
    event TournamentCreated(
        uint256 indexed tournamentId,
        bytes32[] pairs,
        uint40 startTime,
        uint40 endTime,
        uint128 startBalance,
        uint16 maxLeverage,
        uint80 entryFee,
        uint16 minimumHoldDuration,
        uint64 rebuyLimit,
        uint256 bonusCollateral
    );

    // Emitted when a user is successfully liquidated.
    event Liquidated(uint256 indexed tournamentId, address indexed user);

    // The user does not have a negative (balance + upnl).
    event InvalidLiquidation(uint256 indexed tournamentId, address indexed user, int256 balance, int256 pnl);

    // Emitted when a liquidation bounty is paid.
    event LiquidationBountyPaid(address indexed liquidator, uint256 amount);

    // Emitted when a trade is executed, to provide trade details.
    event TradeExecuted(
        uint256 indexed tournamentId,
        uint256 indexed nonce,
        address indexed user,
        int256 amount,
        int256 executionPrice,
        bytes32 pair
    );

    // Emitted when a trade is executed, to provide new account details.
    event AccountUpdated(
        uint256 indexed tournamentId,
        address indexed user,
        int256 indexed balance,
        int256 amount,
        int256 entryPrice,
        bytes32 pair
    );

    // Emitted when the base slippage scaling factor is updated.
    event BaseSlippageScalingFactorUpdated(uint256 newFactor);

    // Emitted when the slippage scaling factor is updated.
    event SlippageScalingFactorUpdated(uint256 newFactor);

    // Emitted when the liquidation bounty is updated.
    event LiquidationBountyUpdated(uint256 newBounty);

    // Emitted when the counterparty signer is updated.
    event CounterpartySignerUpdated(address newSigner);

    IPyth private immutable _PYTH;
    IRebootTournament private immutable _REBOOT;
    address private immutable _WAPE_CONTRACT_ADDRESS;
    uint64 private constant _FINAL_ENDTIME_GRACE_PERIOD = 5 seconds;
    int256 private constant _BIPS = 10_000;
    int256 private constant _FIRST_SLIPPAGE_BREAKPOINT = 1_000_000;
    int256 private constant _SECOND_SLIPPAGE_BREAKPOINT = 10_000_000;
    uint256 private constant _GLOBAL_CONFIG_MANAGER = _ROLE_42;
    uint256 private constant _TOURNAMENT_MANAGER = _ROLE_69;
    uint256 private constant _PRICE_MANAGER = _ROLE_88;
    uint256 private constant _MAX_BASE_SLIPPAGE_SCALING_FACTOR = 250;
    uint256 private constant _MAX_SLIPPAGE_INCREMENT_SCALING_FACTOR = 10;

    uint256 public constant SIGNATURE_VALIDITY_DURATION = 30 seconds;
    bytes4 private constant _MANUAL_PRICE_PAIR_IDENTIFIER = 0x00420069;

    address public counterpartySigner;
    uint256 public liquidationBounty;
    int256 public baseSlippageScalingFactor;
    int256 public slippageIncrementScalingFactor;

    mapping(uint256 tournamentId => TournamentConfig tournament) public tournaments;
    mapping(bytes32 pair => InternalPrice price) public internalPrices;
    mapping(uint256 nonce => bool isUsed) public usedNonces;

    constructor(
        address pyth,
        address reboot,
        address wape,
        address signer,
        uint256 _liquidationBounty,
        uint256 _baseSlippage,
        uint256 _slippageIncrement
    ) {
        if (pyth == address(0) || reboot == address(0) || wape == address(0)) revert ZeroAddress();

        _initializeOwner(tx.origin);
        _grantRoles(tx.origin, _GLOBAL_CONFIG_MANAGER | _TOURNAMENT_MANAGER);

        _PYTH = IPyth(pyth);
        _REBOOT = IRebootTournament(reboot);
        _WAPE_CONTRACT_ADDRESS = wape;

        liquidationBounty = _liquidationBounty;

        _setCounterpartySigner(signer);
        _setBaseSlippageScalingFactor(_baseSlippage);
        _setSlippageIncrementScalingFactor(_slippageIncrement);
    }

    receive() external payable {}

    /**
     * @notice Creates a new tournament with the given parameters.
     * @param pairs The pairs that are allowed in the tournament (signature enforced).
     * @param startTime The start time of the tournament.
     * @param endTime The end time of the tournament.
     * @param startBalance The starting balance for each user.
     * @param maxLeverage The maximum leverage allowed for each user.
     * @param entryFee The entry fee in $APE for the tournament.
     * @param rebuyLimit The maximum number of rebuys allowed per user, after initial entry.
     * @param bonusCollateral Optional bonus collateral pool.
     */
    function createTournament(
        bytes32[] calldata pairs,
        uint16 minimumHoldDuration,
        uint40 startTime,
        uint40 endTime,
        uint128 startBalance,
        uint16 maxLeverage,
        uint80 entryFee,
        uint64 rebuyLimit,
        uint256 bonusCollateral
    ) external onlyRoles(_TOURNAMENT_MANAGER) returns (uint256 tournamentId) {
        tournamentId = _REBOOT.register(
            IRebootTournament.Config({
                entryFee: entryFee,
                rebuyFee: entryFee,
                isExactFee: true,
                entryLimit: type(uint64).max,
                maxEntriesPerRoom: type(uint64).max,
                rebuyLimit: rebuyLimit,
                startDate: startTime,
                endDate: endTime,
                ticketProfitToTickets: 1 ether,
                creditProfitToTickets: 1 ether,
                creditEntryToTickets: 1 ether,
                entryDuration: endTime - startTime,
                tournamentDuration: 0,
                payoutDuration: 30 days,
                creditRatio: 0,
                creditId: _WAPE_CONTRACT_ADDRESS,
                bonusCollateral: bonusCollateral,
                priceFeedPair: 0x0
            })
        );

        _REBOOT.createRoom(tournamentId, 0, uint64(startTime));

        TournamentConfig storage tournament = tournaments[tournamentId];

        tournament.minimumHoldDuration = minimumHoldDuration;
        tournament.startTime = startTime;
        tournament.endTime = endTime;
        tournament.startBalance = startBalance;
        tournament.maxLeverage = maxLeverage;

        emit TournamentCreated(
            tournamentId,
            pairs,
            startTime,
            endTime,
            startBalance,
            maxLeverage,
            entryFee,
            minimumHoldDuration,
            rebuyLimit,
            bonusCollateral
        );

        return tournamentId;
    }

    /**
     * @notice Enters a user into a tournament.
     * @param tournamentId The ID of the tournament.
     */
    function enterTournament(uint256 tournamentId) external payable {
        _enterTournament(msg.sender, tournamentId);
    }

    /**
     * @notice Enters a user into a tournament
     * @param user The address of the user
     * @param tournamentId The ID of the tournament
     */
    function enterTournamentFor(address user, uint256 tournamentId) external payable {
        _enterTournament(user, tournamentId);
    }

    /**
     * @notice Executes a trade for a user in a tournament.
     * @param tournamentId The ID of the tournament.
     * @param pair The pair to trade. If the pair is not supported by Pyth, it should begin with _MANUAL_PRICE_PAIR_IDENTIFIER.
     * @param priceUpdates The Pyth price update data (empty if pair is not supported by Pyth).
     * @param amountInBips The amount to trade in bips. Positive for long, negative for short.
     * @param trader The address of the trader. If not msg.sender, `signature` must recover to msg.sender.
     * @param minTimestamp The minimum timestamp for the trade.
     * @param nonce The random nonce for the trade.
     * @param signature The signature of the trader, if trader != msg.sender.
     */
    function trade(
        uint256 tournamentId,
        bytes32 pair,
        bytes[] calldata priceUpdates,
        int256 amountInBips,
        address trader,
        uint256 minTimestamp,
        uint256 nonce,
        bytes calldata signature
    ) external {
        uint256 signatureExpirationTimestamp;
        unchecked {
            signatureExpirationTimestamp = minTimestamp + SIGNATURE_VALIDITY_DURATION;
        }

        if (amountInBips == 0) revert InvalidAmount();
        if (block.timestamp < minTimestamp) revert MinTimestampNotMet();
        if (block.timestamp > signatureExpirationTimestamp) revert SignatureExpired();

        TournamentConfig storage tournament = tournaments[tournamentId];
        _assertTournamentOpen(tournament);

        Trade memory currentPosition = tournament.activeTrade[trader];

        bool isReduce = false;

        if (currentPosition.pair != 0x0) {
            if (currentPosition.pair != pair) {
                revert MismatchedPairs();
            } else if (
                // Enforce minimum hold duration if the user has an open position and is reducing or closing it.
                (currentPosition.amountInBips > 0) != (amountInBips > 0)
            ) {
                if (currentPosition.lastUpdatedAt + tournament.minimumHoldDuration > block.timestamp) {
                    revert MinimumHoldDurationNotMet();
                }

                isReduce = true;
            }
        }

        // Prevent signature re-use.
        if (usedNonces[nonce]) revert NonceAlreadyUsed();
        usedNonces[nonce] = true;

        Direction direction = amountInBips > 0 ? Direction.LONG : Direction.SHORT;
        bytes32 hash = SignatureCheckerLib.toEthSignedMessageHash(
            keccak256(abi.encodePacked(trader, tournamentId, pair, direction, minTimestamp, nonce))
        );

        if (msg.sender == trader) {
            // If trader is submitting the trade, ensure counterparty has signed for it.
            if (!SignatureCheckerLib.isValidSignatureNowCalldata(counterpartySigner, hash, signature)) {
                revert InvalidSignature();
            }
        } else if (msg.sender == counterpartySigner) {
            // If counterparty is submitting trade, ensure the trader has signed for it.
            if (!SignatureCheckerLib.isValidSignatureNowCalldata(trader, hash, signature)) {
                revert InvalidSignature();
            }
        } else {
            // In real life this is where a bouncer would break your kneecaps.
            revert InvalidCaller();
        }

        updatePythPriceFeeds(priceUpdates);
        int256 normalizedPrice = _fetchAndNormalizePrice(pair);

        int256 currentUSDNPnlInBips = _currentPnlForPositionAndPrice(currentPosition, normalizedPrice);
        int256 usdnBalance = tournament.userBalance[trader];
        int256 absoluteActivePositionAmountInBips = _abs(currentPosition.amountInBips);

        int256 usdnMaxTradeInBips;
        unchecked {
            // At very large balances, this math will over/underflow and cause unintended side effects.
            // Break the contract. Achieve eternal glory. Bet more.
            int256 usdnTotalAvailableCapital =
                (usdnBalance * _BIPS + currentUSDNPnlInBips) * int256(uint256(tournament.maxLeverage)) / _BIPS;
            int256 absoluteExistingExposure = absoluteActivePositionAmountInBips * normalizedPrice / _BIPS;
            usdnMaxTradeInBips = (
                isReduce
                    ? usdnTotalAvailableCapital + absoluteExistingExposure
                    : usdnTotalAvailableCapital - absoluteExistingExposure
            ) * _BIPS;
        }

        int256 absoluteAmountInBips = _abs(amountInBips);

        // Leave this checked to prevent malicious over/underflow in subsequent calcs.
        int256 tradeSizeInBips = absoluteAmountInBips * normalizedPrice;
        if (tradeSizeInBips > usdnMaxTradeInBips) {
            // Set max trade to 0 if negative, for event clarity.
            if (usdnMaxTradeInBips < 0) usdnMaxTradeInBips = 0;

            revert InsufficientBalance(usdnMaxTradeInBips, tradeSizeInBips);
        }

        int104 openAmount;
        if (isReduce) {
            if (absoluteAmountInBips == absoluteActivePositionAmountInBips) {
                // Position is being closed. Should never be used. Liquidation or glory.
                unchecked {
                    usdnBalance += (currentUSDNPnlInBips / _BIPS);
                }

                // Apply profits and close position.
                tournament.userBalance[trader] = usdnBalance;
                tournament.activeTrade[trader] = Trade(0x0, uint40(block.timestamp), 0, 0);

                emit TradeExecuted(tournamentId, nonce, trader, amountInBips, normalizedPrice, pair);
                emit AccountUpdated(tournamentId, trader, tournament.userBalance[trader], 0, 0, 0x0);
            } else if (absoluteAmountInBips < absoluteActivePositionAmountInBips) {
                // Position is being reduced. For use by cowards only.
                unchecked {
                    openAmount = currentPosition.amountInBips + int104(amountInBips);
                    usdnBalance +=
                        currentUSDNPnlInBips * absoluteAmountInBips / absoluteActivePositionAmountInBips / _BIPS;
                }

                // Apply scaled profits, reduce position, and reset open timstamp.
                tournament.userBalance[trader] = usdnBalance;
                tournament.activeTrade[trader].amountInBips = openAmount;
                tournament.activeTrade[trader].lastUpdatedAt = uint40(block.timestamp);

                emit TradeExecuted(tournamentId, nonce, trader, amountInBips, normalizedPrice, pair);
                emit AccountUpdated(
                    tournamentId, trader, tournament.userBalance[trader], openAmount, currentPosition.entryPrice, pair
                );
            } else {
                // Position is being flipped. For use by the candle chasers.
                // We need to close and apply profits without slippage, then open a new position with slippage.
                unchecked {
                    openAmount = currentPosition.amountInBips + int104(amountInBips);
                    usdnBalance += currentUSDNPnlInBips / _BIPS;
                }

                // Apply profits to user's balance and emit event to represent close with no slippage.
                tournament.userBalance[trader] = usdnBalance;
                emit TradeExecuted(
                    tournamentId, nonce, trader, currentPosition.amountInBips * -1, normalizedPrice, pair
                );

                // Slippage is applied only to the new position.
                int256 newTradeSizeInBips;
                unchecked {
                    newTradeSizeInBips = openAmount * normalizedPrice;
                }
                int256 executionPrice =
                    _calculateEntryPriceWithSlippageApplied(_abs(newTradeSizeInBips), normalizedPrice, direction);
                tournament.activeTrade[trader] =
                    Trade(pair, uint40(block.timestamp), int104(executionPrice), openAmount);

                emit TradeExecuted(tournamentId, nonce, trader, openAmount, executionPrice, pair);
                emit AccountUpdated(
                    tournamentId, trader, tournament.userBalance[trader], openAmount, executionPrice, pair
                );
            }
        } else {
            // Position is being opened or increased. Both are commendable actions.
            int256 executionPrice = _calculateEntryPriceWithSlippageApplied(tradeSizeInBips, normalizedPrice, direction);
            int256 entryPrice;

            unchecked {
                // Scale position size up and calculate new entry price as weighted average of current and new trade.
                openAmount = currentPosition.amountInBips + int104(amountInBips);
                entryPrice = (
                    currentPosition.entryPrice * absoluteActivePositionAmountInBips
                        + executionPrice * absoluteAmountInBips
                ) / (absoluteActivePositionAmountInBips + absoluteAmountInBips);
            }

            tournament.activeTrade[trader] = Trade(pair, uint40(block.timestamp), int104(entryPrice), openAmount);

            emit TradeExecuted(tournamentId, nonce, trader, amountInBips, executionPrice, pair);
            emit AccountUpdated(tournamentId, trader, tournament.userBalance[trader], openAmount, entryPrice, pair);
        }
    }

    /**
     * @notice Liquidates a user in a tournament, as long as their balance + pnl is negative.
     * @param tournamentId The ID of the tournament.
     * @param users The users to liquidate.
     * @param priceUpdates The Pyth price update data.
     */
    function liquidate(uint256 tournamentId, address[] calldata users, bytes[] calldata priceUpdates) external {
        TournamentConfig storage tournament = tournaments[tournamentId];

        _assertTournamentOpen(tournament);
        updatePythPriceFeeds(priceUpdates);

        uint256 liquidationBountyPayout;

        for (uint256 i = 0; i < users.length; i++) {
            int256 currentPnl = _currentPnlFor(tournament, users[i]);

            if (currentPnl + tournament.userBalance[users[i]] < 0) {
                // Get rekt noob.
                tournament.userBalance[users[i]] = 0;
                delete tournament.activeTrade[users[i]];
                unchecked {
                    liquidationBountyPayout += liquidationBounty;
                }

                emit Liquidated(tournamentId, users[i]);
            } else {
                // You're safe for now.
                emit InvalidLiquidation(tournamentId, users[i], tournament.userBalance[users[i]], currentPnl);
            }
        }

        if (liquidationBountyPayout > 0) {
            (bool success,) = msg.sender.call{value: liquidationBountyPayout}("");
            if (!success) revert TransferFailed();

            emit LiquidationBountyPaid(msg.sender, liquidationBountyPayout);
        }
    }

    /**
     * @notice Manual price update.
     * @param priceUpdates The Pyth price update data.
     */
    function updatePythPriceFeeds(bytes[] calldata priceUpdates) public {
        if (priceUpdates.length > 0) {
            uint256 fee = _PYTH.getUpdateFee(priceUpdates);

            _PYTH.updatePriceFeeds{value: fee}(priceUpdates);
        }
    }

    /**
     * @notice Manual price update.
     * @param pairs The pairs to update.
     * @param prices The prices to update.
     */
    function updateManualPriceFeeds(bytes32[] calldata pairs, InternalPrice[] calldata prices) external onlyRoles(_PRICE_MANAGER) {
        if (pairs.length != prices.length) revert ArrayLengthMismatch();

        for (uint256 i = 0; i < pairs.length; i++) {
            InternalPrice memory price = prices[i];
            bytes32 pair = pairs[i];

            if (!_isManualPriceOverride(pair)) revert InvalidPriceUpdates();

            // disallow future timestamps.
            if (price.publishTime > block.timestamp) revert InvalidTimestamp();
            if (price.publishTime <= internalPrices[pair].publishTime) continue;

            internalPrices[pair] = price;
        }
    }

    /**
     * @notice Finalize prices for a tournament.
     * @param tournamentId The ID of the tournament.
     * @param priceUpdates The Pyth price update data.
     * @param pairs The pairs to finalize prices for.
     */
    function finalizePrices(uint256 tournamentId, bytes[] calldata priceUpdates, bytes32[] calldata pairs)
        external
        onlyRoles(_TOURNAMENT_MANAGER)
    {
        TournamentConfig storage tournament = tournaments[tournamentId];

        if (tournament.endTime > block.timestamp) revert TournamentActive();

        uint256 fee = _PYTH.getUpdateFee(priceUpdates);
        PythStructs.PriceFeed[] memory priceFeeds = _PYTH.parsePriceFeedUpdates{value: fee}(
            priceUpdates, pairs, tournament.endTime, tournament.endTime + _FINAL_ENDTIME_GRACE_PERIOD
        );

        for (uint256 i = 0; i < priceFeeds.length; i++) {
            PythStructs.Price memory price = priceFeeds[i].price;

            // convert to InternalPrice to save a storage slot.
            tournament.finalPrices[priceFeeds[i].id] =
                InternalPrice({price: price.price, expo: price.expo, publishTime: uint40(price.publishTime)});
        }
    }

    /**
     * @notice Sets the counterparty signer.
     * @param signer The new counterparty signer.
     */
    function setCounterpartySigner(address signer) external onlyRoles(_GLOBAL_CONFIG_MANAGER) {
        _setCounterpartySigner(signer);
    }

    /**
     * @notice Sets the liquidation bounty.
     * @param bounty The new liquidation bounty.
     */
    function setLiquidationBounty(uint256 bounty) external onlyRoles(_GLOBAL_CONFIG_MANAGER) {
        _setLiquidationBounty(bounty);
    }

    /**
     * @notice Returns the final pyth price for a pair in a tournament.
     * @param tournamentId The ID of the tournament.
     * @param pair The pair to get final pyth price for.
     */
    function finalPrice(uint256 tournamentId, bytes32 pair) external view returns (InternalPrice memory) {
        return tournaments[tournamentId].finalPrices[pair];
    }

    /**
     * @notice Sets the base slippage scaling factor.
     * @param factor The new base slippage scaling factor.
     */
    function setBaseSlippageScalingFactor(uint256 factor) external onlyRoles(_GLOBAL_CONFIG_MANAGER) {
        _setBaseSlippageScalingFactor(factor);
    }

    /**
     * @notice Sets the slippage increment scaling factor.
     * @param factor The new slippage increment scaling factor.
     */
    function setSlippageIncrementScalingFactor(uint256 factor) external onlyRoles(_GLOBAL_CONFIG_MANAGER) {
        _setSlippageIncrementScalingFactor(factor);
    }

    /**
     * @notice Submit results for a tournament.
     * @param tournamentId The ID of the tournament.
     * @param results The results to propose.
     */
    function submitResults(uint256 tournamentId, IRebootTournament.Result[] calldata results)
        external
        onlyRoles(_TOURNAMENT_MANAGER)
    {
        _REBOOT.submitResults(tournamentId, 0, results);
    }

    function cleanup(uint256 tournamentId) external onlyRoles(_TOURNAMENT_MANAGER) {
        _REBOOT.cleanup(tournamentId, 0);
    }

    /**
     * @notice Withdraws the contract balance.
     * @dev If there is a liquidation bounty in place, calling this while a tournament is active will cause liquidations to fail.
     */
    function withdraw() external onlyOwner {
        (bool success,) = msg.sender.call{value: address(this).balance}("");
        if (!success) revert TransferFailed();
    }

    /**
     * @notice Returns the most recent Reboot tournament ID.
     */
    function currentTournamentId() external view returns (uint256) {
        return _REBOOT.tournamentCount();
    }

    /**
     * @notice Returns the active trade for a user in a tournament.
     * @param tournamentId The ID of the tournament.
     * @param user The address of the user.
     */
    function activeTrade(uint256 tournamentId, address user) external view returns (Trade memory) {
        return tournaments[tournamentId].activeTrade[user];
    }

    /**
     * .
     * @notice Returns the balance for a user in a tournament.
     * @param tournamentId The ID of the tournament.
     * @param user The address of the user.
     */
    function userBalance(uint256 tournamentId, address user) external view returns (int256) {
        return tournaments[tournamentId].userBalance[user];
    }

    /**
     * @notice Returns the current UPnL for a user in a tournament.
     * @param tournamentId The ID of the tournament.
     * @param user The address of the user.
     * @dev UPnL does not include the user's balance.
     * @dev Does not perform a price update, so may be stale. Use updatePrices to ensure the most recent prices.
     * @dev accounts for slippage on close.
     */
    function currentPnlFor(uint256 tournamentId, address user) external view returns (int256) {
        TournamentConfig storage tournament = tournaments[tournamentId];

        return _currentPnlFor(tournament, user);
    }

    /**
     * @notice Enters a user into a tournament.
     * @param tournamentId The ID of the tournament.
     */
    function _enterTournament(address user, uint256 tournamentId) internal {
        TournamentConfig storage tournament = tournaments[tournamentId];

        if (tournament.userBalance[user] != 0) {
            revert AlreadyEntered();
        }
        _assertTournamentOpen(tournament);

        // A valid underflow is incredibly impractical.
        uint256 valueToTransfer;
        unchecked {
            valueToTransfer = msg.value - liquidationBounty;
        }
        uint256 entryFee = _REBOOT.getTournament(tournamentId).entryFee;

        // If msg.sender == user, they can use their reboot credits to enter. If not, msg.value must be used for entry fee.
        if (msg.sender != user && valueToTransfer < entryFee) revert InsufficientEntryFee();

        _REBOOT.enter{value: valueToTransfer}(
            IRebootTournament.EntryParams(user, tournamentId, 0, address(0), 0, entryFee)
        );

        tournament.userBalance[user] = int256(int128(tournament.startBalance));
    }

    function _setCounterpartySigner(address signer) internal {
        if (signer == address(0)) revert ZeroAddress();

        counterpartySigner = signer;

        emit CounterpartySignerUpdated(signer);
    }

    function _setBaseSlippageScalingFactor(uint256 factor) internal {
        // revert if slippage scaling factor > _MAX_BASE_SLIPPAGE_SCALING_FACTOR.
        if (factor > _MAX_BASE_SLIPPAGE_SCALING_FACTOR) revert SlippageTooHigh();

        baseSlippageScalingFactor = int256(factor);

        emit BaseSlippageScalingFactorUpdated(factor);
    }

    function _setSlippageIncrementScalingFactor(uint256 factor) internal {
        // revert if slippage scaling factor > _MAX_SLIPPAGE_INCREMENT_SCALING_FACTOR.
        if (factor > _MAX_SLIPPAGE_INCREMENT_SCALING_FACTOR) revert SlippageTooHigh();

        slippageIncrementScalingFactor = int256(factor);

        emit SlippageScalingFactorUpdated(factor);
    }

    function _setLiquidationBounty(uint256 bounty) internal {
        // bounty should typically be ~1 apecoin or less.
        if (bounty > 1_000 ether) revert LiquidationBountyTooHigh();

        liquidationBounty = bounty;

        emit LiquidationBountyUpdated(bounty);
    }

    function _updateAndFetchPythPrice(bytes32 pair, bytes[] calldata priceUpdates)
        internal
        returns (PythStructs.Price memory)
    {
        updatePythPriceFeeds(priceUpdates);
        return _PYTH.getPrice(pair);
    }

    function _fetchAndNormalizePrice(bytes32 pair) internal view returns (int256) {
        if (bytes4(pair) == _MANUAL_PRICE_PAIR_IDENTIFIER) {
            InternalPrice memory price = internalPrices[pair];

            if (price.publishTime < block.timestamp - _PYTH.getValidTimePeriod()) {
                revert StalePrice();
            }

            return _normalizePrice(price.price, price.expo);
        } else {
            PythStructs.Price memory price = _PYTH.getPrice(pair);
            return _normalizePrice(price.price, price.expo);
        }
    }

    function _currentPnlFor(TournamentConfig storage tournament, address user) internal view returns (int256) {
        Trade memory activePosition = tournament.activeTrade[user];
        bytes32 pair = activePosition.pair;
        if (pair == 0x0) {
            return 0;
        }

        int256 normalizedPrice;
        if (tournament.finalPrices[pair].price != 0) {
            InternalPrice memory price = tournament.finalPrices[pair];
            normalizedPrice = _normalizePrice(price.price, price.expo);
        } else {
            normalizedPrice = _fetchAndNormalizePrice(pair);
        }

        return _currentPnlForPositionAndPrice(activePosition, normalizedPrice) / _BIPS;
    }

    function _assertTournamentOpen(TournamentConfig storage tournament) internal view {
        if (block.timestamp < tournament.startTime || block.timestamp > tournament.endTime) {
            revert NotActive();
        }
    }

    // No free rides.
    function _calculateEntryPriceWithSlippageApplied(int256 tradeSizeInBips, int256 rawEntryPrice, Direction direction)
        internal
        view
        returns (int256 executionPrice)
    {
        int256 floorTradeSize;
        unchecked {
            floorTradeSize = tradeSizeInBips / (_BIPS * 1e18);
        }
        int256 directionModifier = direction == Direction.LONG ? int256(1) : int256(-1);

        if (floorTradeSize < _FIRST_SLIPPAGE_BREAKPOINT) {
            // Apply 1x base slippage to raw entry price.
            unchecked {
                int256 slippage = rawEntryPrice * baseSlippageScalingFactor / 1_000_000;
                executionPrice = directionModifier * slippage + rawEntryPrice;
            }
        } else if (floorTradeSize < _SECOND_SLIPPAGE_BREAKPOINT) {
            // Apply 2x base slippage to raw entry price.
            unchecked {
                int256 slippage = rawEntryPrice * baseSlippageScalingFactor / 500_000;
                executionPrice = directionModifier * slippage + rawEntryPrice;
            }
        } else {
            // Apply 2x base slippage + additional slippage for every order of magnitude increase.
            int256 additionalSlippage = 0;
            unchecked {
                int256 baseSlippage = rawEntryPrice * baseSlippageScalingFactor / 500_000;
                int256 slippageIncrement = rawEntryPrice * slippageIncrementScalingFactor / 10_000_000;

                while (floorTradeSize >= _SECOND_SLIPPAGE_BREAKPOINT) {
                    additionalSlippage += slippageIncrement;
                    floorTradeSize = floorTradeSize * 7943 / 10000; // Reduce by 1/10th of a magnitude (20.57%).
                }

                int256 totalSlippage = baseSlippage + additionalSlippage;
                executionPrice = directionModifier * totalSlippage + rawEntryPrice;
            }
        }
    }

    function _normalizePrice(int64 price, int32 expo) internal pure returns (int256) {
        unchecked {
            if (expo < -18) {
                return int256(price) / int256(10 ** uint256(uint32(-(18 + expo))));
            } else {
                return int256(price) * int256(10 ** uint256(uint32(18 + expo)));
            }
        }
    }

    function _currentPnlForPositionAndPrice(Trade memory activePosition, int256 normalizedPrice)
        internal
        pure
        returns (int256)
    {
        unchecked {
            return (normalizedPrice - activePosition.entryPrice) * activePosition.amountInBips;
        }
    }

    function _isManualPriceOverride(bytes32 pair) internal pure returns (bool) {
        return bytes4(pair) == _MANUAL_PRICE_PAIR_IDENTIFIER;
    }

    function _abs(int256 x) internal pure returns (int256) {
        return x >= 0 ? x : -x;
    }
}

/**
 * _     _ _______ _______  _____       _______        _____ _______ _     _ _____ __   _  ______  
 *  |____/  |______ |______ |_____]      |       |        |   |       |____/    |   | \  | |  ____  
 *  |    \_ |______ |______ |            |_____  |_____ __|__ |_____  |    \_ __|__ |  \_| |_____| .
 *
 *   ______         _____   ______ __   __      _______ _  _  _ _______ _____ _______ _______  
 *  |  ____ |      |     | |_____/   \_/        |_____| |  |  | |_____|   |      |    |______  
 *  |_____| |_____ |_____| |    \_    |         |     | |__|__| |     | __|__    |    ______| .
 *
 *  ______  _______ _______      _______  _____   ______ _______  
 *  |_____] |______    |         |  |  | |     | |_____/ |______  
 *  |_____] |______    |         |  |  | |_____| |    \_ |______ .
 */

File 2 of 9 : IPyth.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "./PythStructs.sol";
import "./IPythEvents.sol";

/// @title Consume prices from the Pyth Network (https://pyth.network/).
/// @dev Please refer to the guidance at https://docs.pyth.network/consumers/best-practices for how to consume prices safely.
/// @author Pyth Data Association
interface IPyth is IPythEvents {
    /// @notice Returns the period (in seconds) that a price feed is considered valid since its publish time
    function getValidTimePeriod() external view returns (uint validTimePeriod);

    /// @notice Returns the price and confidence interval.
    /// @dev Reverts if the price has not been updated within the last `getValidTimePeriod()` seconds.
    /// @param id The Pyth Price Feed ID of which to fetch the price and confidence interval.
    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
    function getPrice(
        bytes32 id
    ) external view returns (PythStructs.Price memory price);

    /// @notice Returns the exponentially-weighted moving average price and confidence interval.
    /// @dev Reverts if the EMA price is not available.
    /// @param id The Pyth Price Feed ID of which to fetch the EMA price and confidence interval.
    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
    function getEmaPrice(
        bytes32 id
    ) external view returns (PythStructs.Price memory price);

    /// @notice Returns the price of a price feed without any sanity checks.
    /// @dev This function returns the most recent price update in this contract without any recency checks.
    /// This function is unsafe as the returned price update may be arbitrarily far in the past.
    ///
    /// Users of this function should check the `publishTime` in the price to ensure that the returned price is
    /// sufficiently recent for their application. If you are considering using this function, it may be
    /// safer / easier to use either `getPrice` or `getPriceNoOlderThan`.
    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
    function getPriceUnsafe(
        bytes32 id
    ) external view returns (PythStructs.Price memory price);

    /// @notice Returns the price that is no older than `age` seconds of the current time.
    /// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in
    /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
    /// recently.
    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
    function getPriceNoOlderThan(
        bytes32 id,
        uint age
    ) external view returns (PythStructs.Price memory price);

    /// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks.
    /// @dev This function returns the same price as `getEmaPrice` in the case where the price is available.
    /// However, if the price is not recent this function returns the latest available price.
    ///
    /// The returned price can be from arbitrarily far in the past; this function makes no guarantees that
    /// the returned price is recent or useful for any particular application.
    ///
    /// Users of this function should check the `publishTime` in the price to ensure that the returned price is
    /// sufficiently recent for their application. If you are considering using this function, it may be
    /// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`.
    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
    function getEmaPriceUnsafe(
        bytes32 id
    ) external view returns (PythStructs.Price memory price);

    /// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds
    /// of the current time.
    /// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in
    /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
    /// recently.
    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
    function getEmaPriceNoOlderThan(
        bytes32 id,
        uint age
    ) external view returns (PythStructs.Price memory price);

    /// @notice Update price feeds with given update messages.
    /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
    /// `getUpdateFee` with the length of the `updateData` array.
    /// Prices will be updated if they are more recent than the current stored prices.
    /// The call will succeed even if the update is not the most recent.
    /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid.
    /// @param updateData Array of price update data.
    function updatePriceFeeds(bytes[] calldata updateData) external payable;

    /// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is
    /// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the
    /// given `publishTimes` for the price feeds and does not read the actual price update publish time within `updateData`.
    ///
    /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
    /// `getUpdateFee` with the length of the `updateData` array.
    ///
    /// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime
    /// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have
    /// a newer or equal publish time than the given publish time, it will reject the transaction to save gas.
    /// Otherwise, it calls updatePriceFeeds method to update the prices.
    ///
    /// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid.
    /// @param updateData Array of price update data.
    /// @param priceIds Array of price ids.
    /// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]`
    function updatePriceFeedsIfNecessary(
        bytes[] calldata updateData,
        bytes32[] calldata priceIds,
        uint64[] calldata publishTimes
    ) external payable;

    /// @notice Returns the required fee to update an array of price updates.
    /// @param updateData Array of price update data.
    /// @return feeAmount The required fee in Wei.
    function getUpdateFee(
        bytes[] calldata updateData
    ) external view returns (uint feeAmount);

    /// @notice Parse `updateData` and return price feeds of the given `priceIds` if they are all published
    /// within `minPublishTime` and `maxPublishTime`.
    ///
    /// You can use this method if you want to use a Pyth price at a fixed time and not the most recent price;
    /// otherwise, please consider using `updatePriceFeeds`. This method does not store the price updates on-chain.
    ///
    /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
    /// `getUpdateFee` with the length of the `updateData` array.
    ///
    ///
    /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is
    /// no update for any of the given `priceIds` within the given time range.
    /// @param updateData Array of price update data.
    /// @param priceIds Array of price ids.
    /// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.
    /// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.
    /// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
    function parsePriceFeedUpdates(
        bytes[] calldata updateData,
        bytes32[] calldata priceIds,
        uint64 minPublishTime,
        uint64 maxPublishTime
    ) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);
}

File 3 of 9 : PythStructs.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

contract PythStructs {
    // A price with a degree of uncertainty, represented as a price +- a confidence interval.
    //
    // The confidence interval roughly corresponds to the standard error of a normal distribution.
    // Both the price and confidence are stored in a fixed-point numeric representation,
    // `x * (10^expo)`, where `expo` is the exponent.
    //
    // Please refer to the documentation at https://docs.pyth.network/consumers/best-practices for how
    // to how this price safely.
    struct Price {
        // Price
        int64 price;
        // Confidence interval around the price
        uint64 conf;
        // Price exponent
        int32 expo;
        // Unix timestamp describing when the price was published
        uint publishTime;
    }

    // PriceFeed represents a current aggregate price from pyth publisher feeds.
    struct PriceFeed {
        // The price ID.
        bytes32 id;
        // Latest available price
        Price price;
        // Latest available exponentially-weighted moving average price
        Price emaPrice;
    }
}

File 4 of 9 : OwnableRoles.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

/// @notice Simple single owner and multiroles authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173)
/// for compatibility, the nomenclature for the 2-step ownership handover and roles
/// may be unique to this codebase.
abstract contract OwnableRoles is Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The `user`'s roles is updated to `roles`.
    /// Each bit of `roles` represents whether the role is set.
    event RolesUpdated(address indexed user, uint256 indexed roles);

    /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`.
    uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE =
        0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26;

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

    /// @dev The role slot of `user` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED))
    ///     let roleSlot := keccak256(0x00, 0x20)
    /// ```
    /// This automatically ignores the upper bits of the `user` in case
    /// they are not clean, as well as keep the `keccak256` under 32-bytes.
    ///
    /// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`.
    uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Overwrite the roles directly without authorization guard.
    function _setRoles(address user, uint256 roles) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            // Store the new value.
            sstore(keccak256(0x0c, 0x20), roles)
            // Emit the {RolesUpdated} event.
            log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles)
        }
    }

    /// @dev Updates the roles directly without authorization guard.
    /// If `on` is true, each set bit of `roles` will be turned on,
    /// otherwise, each set bit of `roles` will be turned off.
    function _updateRoles(address user, uint256 roles, bool on) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            let roleSlot := keccak256(0x0c, 0x20)
            // Load the current value.
            let current := sload(roleSlot)
            // Compute the updated roles if `on` is true.
            let updated := or(current, roles)
            // Compute the updated roles if `on` is false.
            // Use `and` to compute the intersection of `current` and `roles`,
            // `xor` it with `current` to flip the bits in the intersection.
            if iszero(on) { updated := xor(current, and(current, roles)) }
            // Then, store the new value.
            sstore(roleSlot, updated)
            // Emit the {RolesUpdated} event.
            log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated)
        }
    }

    /// @dev Grants the roles directly without authorization guard.
    /// Each bit of `roles` represents the role to turn on.
    function _grantRoles(address user, uint256 roles) internal virtual {
        _updateRoles(user, roles, true);
    }

    /// @dev Removes the roles directly without authorization guard.
    /// Each bit of `roles` represents the role to turn off.
    function _removeRoles(address user, uint256 roles) internal virtual {
        _updateRoles(user, roles, false);
    }

    /// @dev Throws if the sender does not have any of the `roles`.
    function _checkRoles(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, caller())
            // Load the stored value, and if the `and` intersection
            // of the value and `roles` is zero, revert.
            if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Throws if the sender is not the owner,
    /// and does not have any of the `roles`.
    /// Checks for ownership first, then lazily checks for roles.
    function _checkOwnerOrRoles(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner.
            // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
            if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
                // Compute the role slot.
                mstore(0x0c, _ROLE_SLOT_SEED)
                mstore(0x00, caller())
                // Load the stored value, and if the `and` intersection
                // of the value and `roles` is zero, revert.
                if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                    mstore(0x00, 0x82b42900) // `Unauthorized()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Throws if the sender does not have any of the `roles`,
    /// and is not the owner.
    /// Checks for roles first, then lazily checks for ownership.
    function _checkRolesOrOwner(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, caller())
            // Load the stored value, and if the `and` intersection
            // of the value and `roles` is zero, revert.
            if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                // If the caller is not the stored owner.
                // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
                if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
                    mstore(0x00, 0x82b42900) // `Unauthorized()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`.
    /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
    /// Not recommended to be called on-chain.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) {
        /// @solidity memory-safe-assembly
        assembly {
            for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } {
                // We don't need to mask the values of `ordinals`, as Solidity
                // cleans dirty upper bits when storing variables into memory.
                roles := or(shl(mload(add(ordinals, i)), 1), roles)
            }
        }
    }

    /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap.
    /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
    /// Not recommended to be called on-chain.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the pointer to the free memory.
            ordinals := mload(0x40)
            let ptr := add(ordinals, 0x20)
            let o := 0
            // The absence of lookup tables, De Bruijn, etc., here is intentional for
            // smaller bytecode, as this function is not meant to be called on-chain.
            for { let t := roles } 1 {} {
                mstore(ptr, o)
                // `shr` 5 is equivalent to multiplying by 0x20.
                // Push back into the ordinals array if the bit is set.
                ptr := add(ptr, shl(5, and(t, 1)))
                o := add(o, 1)
                t := shr(o, roles)
                if iszero(t) { break }
            }
            // Store the length of `ordinals`.
            mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20))))
            // Allocate the memory.
            mstore(0x40, ptr)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to grant `user` `roles`.
    /// If the `user` already has a role, then it will be an no-op for the role.
    function grantRoles(address user, uint256 roles) public payable virtual onlyOwner {
        _grantRoles(user, roles);
    }

    /// @dev Allows the owner to remove `user` `roles`.
    /// If the `user` does not have a role, then it will be an no-op for the role.
    function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner {
        _removeRoles(user, roles);
    }

    /// @dev Allow the caller to remove their own roles.
    /// If the caller does not have a role, then it will be an no-op for the role.
    function renounceRoles(uint256 roles) public payable virtual {
        _removeRoles(msg.sender, roles);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the roles of `user`.
    function rolesOf(address user) public view virtual returns (uint256 roles) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            // Load the stored value.
            roles := sload(keccak256(0x0c, 0x20))
        }
    }

    /// @dev Returns whether `user` has any of `roles`.
    function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) {
        return rolesOf(user) & roles != 0;
    }

    /// @dev Returns whether `user` has all of `roles`.
    function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) {
        return rolesOf(user) & roles == roles;
    }

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

    /// @dev Marks a function as only callable by an account with `roles`.
    modifier onlyRoles(uint256 roles) virtual {
        _checkRoles(roles);
        _;
    }

    /// @dev Marks a function as only callable by the owner or by an account
    /// with `roles`. Checks for ownership first, then lazily checks for roles.
    modifier onlyOwnerOrRoles(uint256 roles) virtual {
        _checkOwnerOrRoles(roles);
        _;
    }

    /// @dev Marks a function as only callable by an account with `roles`
    /// or the owner. Checks for roles first, then lazily checks for ownership.
    modifier onlyRolesOrOwner(uint256 roles) virtual {
        _checkRolesOrOwner(roles);
        _;
    }

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

    // IYKYK

    uint256 internal constant _ROLE_0 = 1 << 0;
    uint256 internal constant _ROLE_1 = 1 << 1;
    uint256 internal constant _ROLE_2 = 1 << 2;
    uint256 internal constant _ROLE_3 = 1 << 3;
    uint256 internal constant _ROLE_4 = 1 << 4;
    uint256 internal constant _ROLE_5 = 1 << 5;
    uint256 internal constant _ROLE_6 = 1 << 6;
    uint256 internal constant _ROLE_7 = 1 << 7;
    uint256 internal constant _ROLE_8 = 1 << 8;
    uint256 internal constant _ROLE_9 = 1 << 9;
    uint256 internal constant _ROLE_10 = 1 << 10;
    uint256 internal constant _ROLE_11 = 1 << 11;
    uint256 internal constant _ROLE_12 = 1 << 12;
    uint256 internal constant _ROLE_13 = 1 << 13;
    uint256 internal constant _ROLE_14 = 1 << 14;
    uint256 internal constant _ROLE_15 = 1 << 15;
    uint256 internal constant _ROLE_16 = 1 << 16;
    uint256 internal constant _ROLE_17 = 1 << 17;
    uint256 internal constant _ROLE_18 = 1 << 18;
    uint256 internal constant _ROLE_19 = 1 << 19;
    uint256 internal constant _ROLE_20 = 1 << 20;
    uint256 internal constant _ROLE_21 = 1 << 21;
    uint256 internal constant _ROLE_22 = 1 << 22;
    uint256 internal constant _ROLE_23 = 1 << 23;
    uint256 internal constant _ROLE_24 = 1 << 24;
    uint256 internal constant _ROLE_25 = 1 << 25;
    uint256 internal constant _ROLE_26 = 1 << 26;
    uint256 internal constant _ROLE_27 = 1 << 27;
    uint256 internal constant _ROLE_28 = 1 << 28;
    uint256 internal constant _ROLE_29 = 1 << 29;
    uint256 internal constant _ROLE_30 = 1 << 30;
    uint256 internal constant _ROLE_31 = 1 << 31;
    uint256 internal constant _ROLE_32 = 1 << 32;
    uint256 internal constant _ROLE_33 = 1 << 33;
    uint256 internal constant _ROLE_34 = 1 << 34;
    uint256 internal constant _ROLE_35 = 1 << 35;
    uint256 internal constant _ROLE_36 = 1 << 36;
    uint256 internal constant _ROLE_37 = 1 << 37;
    uint256 internal constant _ROLE_38 = 1 << 38;
    uint256 internal constant _ROLE_39 = 1 << 39;
    uint256 internal constant _ROLE_40 = 1 << 40;
    uint256 internal constant _ROLE_41 = 1 << 41;
    uint256 internal constant _ROLE_42 = 1 << 42;
    uint256 internal constant _ROLE_43 = 1 << 43;
    uint256 internal constant _ROLE_44 = 1 << 44;
    uint256 internal constant _ROLE_45 = 1 << 45;
    uint256 internal constant _ROLE_46 = 1 << 46;
    uint256 internal constant _ROLE_47 = 1 << 47;
    uint256 internal constant _ROLE_48 = 1 << 48;
    uint256 internal constant _ROLE_49 = 1 << 49;
    uint256 internal constant _ROLE_50 = 1 << 50;
    uint256 internal constant _ROLE_51 = 1 << 51;
    uint256 internal constant _ROLE_52 = 1 << 52;
    uint256 internal constant _ROLE_53 = 1 << 53;
    uint256 internal constant _ROLE_54 = 1 << 54;
    uint256 internal constant _ROLE_55 = 1 << 55;
    uint256 internal constant _ROLE_56 = 1 << 56;
    uint256 internal constant _ROLE_57 = 1 << 57;
    uint256 internal constant _ROLE_58 = 1 << 58;
    uint256 internal constant _ROLE_59 = 1 << 59;
    uint256 internal constant _ROLE_60 = 1 << 60;
    uint256 internal constant _ROLE_61 = 1 << 61;
    uint256 internal constant _ROLE_62 = 1 << 62;
    uint256 internal constant _ROLE_63 = 1 << 63;
    uint256 internal constant _ROLE_64 = 1 << 64;
    uint256 internal constant _ROLE_65 = 1 << 65;
    uint256 internal constant _ROLE_66 = 1 << 66;
    uint256 internal constant _ROLE_67 = 1 << 67;
    uint256 internal constant _ROLE_68 = 1 << 68;
    uint256 internal constant _ROLE_69 = 1 << 69;
    uint256 internal constant _ROLE_70 = 1 << 70;
    uint256 internal constant _ROLE_71 = 1 << 71;
    uint256 internal constant _ROLE_72 = 1 << 72;
    uint256 internal constant _ROLE_73 = 1 << 73;
    uint256 internal constant _ROLE_74 = 1 << 74;
    uint256 internal constant _ROLE_75 = 1 << 75;
    uint256 internal constant _ROLE_76 = 1 << 76;
    uint256 internal constant _ROLE_77 = 1 << 77;
    uint256 internal constant _ROLE_78 = 1 << 78;
    uint256 internal constant _ROLE_79 = 1 << 79;
    uint256 internal constant _ROLE_80 = 1 << 80;
    uint256 internal constant _ROLE_81 = 1 << 81;
    uint256 internal constant _ROLE_82 = 1 << 82;
    uint256 internal constant _ROLE_83 = 1 << 83;
    uint256 internal constant _ROLE_84 = 1 << 84;
    uint256 internal constant _ROLE_85 = 1 << 85;
    uint256 internal constant _ROLE_86 = 1 << 86;
    uint256 internal constant _ROLE_87 = 1 << 87;
    uint256 internal constant _ROLE_88 = 1 << 88;
    uint256 internal constant _ROLE_89 = 1 << 89;
    uint256 internal constant _ROLE_90 = 1 << 90;
    uint256 internal constant _ROLE_91 = 1 << 91;
    uint256 internal constant _ROLE_92 = 1 << 92;
    uint256 internal constant _ROLE_93 = 1 << 93;
    uint256 internal constant _ROLE_94 = 1 << 94;
    uint256 internal constant _ROLE_95 = 1 << 95;
    uint256 internal constant _ROLE_96 = 1 << 96;
    uint256 internal constant _ROLE_97 = 1 << 97;
    uint256 internal constant _ROLE_98 = 1 << 98;
    uint256 internal constant _ROLE_99 = 1 << 99;
    uint256 internal constant _ROLE_100 = 1 << 100;
    uint256 internal constant _ROLE_101 = 1 << 101;
    uint256 internal constant _ROLE_102 = 1 << 102;
    uint256 internal constant _ROLE_103 = 1 << 103;
    uint256 internal constant _ROLE_104 = 1 << 104;
    uint256 internal constant _ROLE_105 = 1 << 105;
    uint256 internal constant _ROLE_106 = 1 << 106;
    uint256 internal constant _ROLE_107 = 1 << 107;
    uint256 internal constant _ROLE_108 = 1 << 108;
    uint256 internal constant _ROLE_109 = 1 << 109;
    uint256 internal constant _ROLE_110 = 1 << 110;
    uint256 internal constant _ROLE_111 = 1 << 111;
    uint256 internal constant _ROLE_112 = 1 << 112;
    uint256 internal constant _ROLE_113 = 1 << 113;
    uint256 internal constant _ROLE_114 = 1 << 114;
    uint256 internal constant _ROLE_115 = 1 << 115;
    uint256 internal constant _ROLE_116 = 1 << 116;
    uint256 internal constant _ROLE_117 = 1 << 117;
    uint256 internal constant _ROLE_118 = 1 << 118;
    uint256 internal constant _ROLE_119 = 1 << 119;
    uint256 internal constant _ROLE_120 = 1 << 120;
    uint256 internal constant _ROLE_121 = 1 << 121;
    uint256 internal constant _ROLE_122 = 1 << 122;
    uint256 internal constant _ROLE_123 = 1 << 123;
    uint256 internal constant _ROLE_124 = 1 << 124;
    uint256 internal constant _ROLE_125 = 1 << 125;
    uint256 internal constant _ROLE_126 = 1 << 126;
    uint256 internal constant _ROLE_127 = 1 << 127;
    uint256 internal constant _ROLE_128 = 1 << 128;
    uint256 internal constant _ROLE_129 = 1 << 129;
    uint256 internal constant _ROLE_130 = 1 << 130;
    uint256 internal constant _ROLE_131 = 1 << 131;
    uint256 internal constant _ROLE_132 = 1 << 132;
    uint256 internal constant _ROLE_133 = 1 << 133;
    uint256 internal constant _ROLE_134 = 1 << 134;
    uint256 internal constant _ROLE_135 = 1 << 135;
    uint256 internal constant _ROLE_136 = 1 << 136;
    uint256 internal constant _ROLE_137 = 1 << 137;
    uint256 internal constant _ROLE_138 = 1 << 138;
    uint256 internal constant _ROLE_139 = 1 << 139;
    uint256 internal constant _ROLE_140 = 1 << 140;
    uint256 internal constant _ROLE_141 = 1 << 141;
    uint256 internal constant _ROLE_142 = 1 << 142;
    uint256 internal constant _ROLE_143 = 1 << 143;
    uint256 internal constant _ROLE_144 = 1 << 144;
    uint256 internal constant _ROLE_145 = 1 << 145;
    uint256 internal constant _ROLE_146 = 1 << 146;
    uint256 internal constant _ROLE_147 = 1 << 147;
    uint256 internal constant _ROLE_148 = 1 << 148;
    uint256 internal constant _ROLE_149 = 1 << 149;
    uint256 internal constant _ROLE_150 = 1 << 150;
    uint256 internal constant _ROLE_151 = 1 << 151;
    uint256 internal constant _ROLE_152 = 1 << 152;
    uint256 internal constant _ROLE_153 = 1 << 153;
    uint256 internal constant _ROLE_154 = 1 << 154;
    uint256 internal constant _ROLE_155 = 1 << 155;
    uint256 internal constant _ROLE_156 = 1 << 156;
    uint256 internal constant _ROLE_157 = 1 << 157;
    uint256 internal constant _ROLE_158 = 1 << 158;
    uint256 internal constant _ROLE_159 = 1 << 159;
    uint256 internal constant _ROLE_160 = 1 << 160;
    uint256 internal constant _ROLE_161 = 1 << 161;
    uint256 internal constant _ROLE_162 = 1 << 162;
    uint256 internal constant _ROLE_163 = 1 << 163;
    uint256 internal constant _ROLE_164 = 1 << 164;
    uint256 internal constant _ROLE_165 = 1 << 165;
    uint256 internal constant _ROLE_166 = 1 << 166;
    uint256 internal constant _ROLE_167 = 1 << 167;
    uint256 internal constant _ROLE_168 = 1 << 168;
    uint256 internal constant _ROLE_169 = 1 << 169;
    uint256 internal constant _ROLE_170 = 1 << 170;
    uint256 internal constant _ROLE_171 = 1 << 171;
    uint256 internal constant _ROLE_172 = 1 << 172;
    uint256 internal constant _ROLE_173 = 1 << 173;
    uint256 internal constant _ROLE_174 = 1 << 174;
    uint256 internal constant _ROLE_175 = 1 << 175;
    uint256 internal constant _ROLE_176 = 1 << 176;
    uint256 internal constant _ROLE_177 = 1 << 177;
    uint256 internal constant _ROLE_178 = 1 << 178;
    uint256 internal constant _ROLE_179 = 1 << 179;
    uint256 internal constant _ROLE_180 = 1 << 180;
    uint256 internal constant _ROLE_181 = 1 << 181;
    uint256 internal constant _ROLE_182 = 1 << 182;
    uint256 internal constant _ROLE_183 = 1 << 183;
    uint256 internal constant _ROLE_184 = 1 << 184;
    uint256 internal constant _ROLE_185 = 1 << 185;
    uint256 internal constant _ROLE_186 = 1 << 186;
    uint256 internal constant _ROLE_187 = 1 << 187;
    uint256 internal constant _ROLE_188 = 1 << 188;
    uint256 internal constant _ROLE_189 = 1 << 189;
    uint256 internal constant _ROLE_190 = 1 << 190;
    uint256 internal constant _ROLE_191 = 1 << 191;
    uint256 internal constant _ROLE_192 = 1 << 192;
    uint256 internal constant _ROLE_193 = 1 << 193;
    uint256 internal constant _ROLE_194 = 1 << 194;
    uint256 internal constant _ROLE_195 = 1 << 195;
    uint256 internal constant _ROLE_196 = 1 << 196;
    uint256 internal constant _ROLE_197 = 1 << 197;
    uint256 internal constant _ROLE_198 = 1 << 198;
    uint256 internal constant _ROLE_199 = 1 << 199;
    uint256 internal constant _ROLE_200 = 1 << 200;
    uint256 internal constant _ROLE_201 = 1 << 201;
    uint256 internal constant _ROLE_202 = 1 << 202;
    uint256 internal constant _ROLE_203 = 1 << 203;
    uint256 internal constant _ROLE_204 = 1 << 204;
    uint256 internal constant _ROLE_205 = 1 << 205;
    uint256 internal constant _ROLE_206 = 1 << 206;
    uint256 internal constant _ROLE_207 = 1 << 207;
    uint256 internal constant _ROLE_208 = 1 << 208;
    uint256 internal constant _ROLE_209 = 1 << 209;
    uint256 internal constant _ROLE_210 = 1 << 210;
    uint256 internal constant _ROLE_211 = 1 << 211;
    uint256 internal constant _ROLE_212 = 1 << 212;
    uint256 internal constant _ROLE_213 = 1 << 213;
    uint256 internal constant _ROLE_214 = 1 << 214;
    uint256 internal constant _ROLE_215 = 1 << 215;
    uint256 internal constant _ROLE_216 = 1 << 216;
    uint256 internal constant _ROLE_217 = 1 << 217;
    uint256 internal constant _ROLE_218 = 1 << 218;
    uint256 internal constant _ROLE_219 = 1 << 219;
    uint256 internal constant _ROLE_220 = 1 << 220;
    uint256 internal constant _ROLE_221 = 1 << 221;
    uint256 internal constant _ROLE_222 = 1 << 222;
    uint256 internal constant _ROLE_223 = 1 << 223;
    uint256 internal constant _ROLE_224 = 1 << 224;
    uint256 internal constant _ROLE_225 = 1 << 225;
    uint256 internal constant _ROLE_226 = 1 << 226;
    uint256 internal constant _ROLE_227 = 1 << 227;
    uint256 internal constant _ROLE_228 = 1 << 228;
    uint256 internal constant _ROLE_229 = 1 << 229;
    uint256 internal constant _ROLE_230 = 1 << 230;
    uint256 internal constant _ROLE_231 = 1 << 231;
    uint256 internal constant _ROLE_232 = 1 << 232;
    uint256 internal constant _ROLE_233 = 1 << 233;
    uint256 internal constant _ROLE_234 = 1 << 234;
    uint256 internal constant _ROLE_235 = 1 << 235;
    uint256 internal constant _ROLE_236 = 1 << 236;
    uint256 internal constant _ROLE_237 = 1 << 237;
    uint256 internal constant _ROLE_238 = 1 << 238;
    uint256 internal constant _ROLE_239 = 1 << 239;
    uint256 internal constant _ROLE_240 = 1 << 240;
    uint256 internal constant _ROLE_241 = 1 << 241;
    uint256 internal constant _ROLE_242 = 1 << 242;
    uint256 internal constant _ROLE_243 = 1 << 243;
    uint256 internal constant _ROLE_244 = 1 << 244;
    uint256 internal constant _ROLE_245 = 1 << 245;
    uint256 internal constant _ROLE_246 = 1 << 246;
    uint256 internal constant _ROLE_247 = 1 << 247;
    uint256 internal constant _ROLE_248 = 1 << 248;
    uint256 internal constant _ROLE_249 = 1 << 249;
    uint256 internal constant _ROLE_250 = 1 << 250;
    uint256 internal constant _ROLE_251 = 1 << 251;
    uint256 internal constant _ROLE_252 = 1 << 252;
    uint256 internal constant _ROLE_253 = 1 << 253;
    uint256 internal constant _ROLE_254 = 1 << 254;
    uint256 internal constant _ROLE_255 = 1 << 255;
}

File 5 of 9 : SignatureCheckerLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Signature verification helper that supports both ECDSA signatures from EOAs
/// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SignatureCheckerLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol)
///
/// @dev Note:
/// - The signature checking functions use the ecrecover precompile (0x1).
/// - The `bytes memory signature` variants use the identity precompile (0x4)
///   to copy memory internally.
/// - Unlike ECDSA signatures, contract signatures are revocable.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
///   regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
///   See: https://eips.ethereum.org/EIPS/eip-2098
///   This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT use signatures as unique identifiers:
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
///   EIP-712 also enables readable signing of typed data for better user safety.
/// This implementation does NOT check if a signature is non-malleable.
library SignatureCheckerLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               SIGNATURE CHECKING OPERATIONS                */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns whether `signature` is valid for `signer` and `hash`.
    /// If `signer` is a smart contract, the signature is validated with ERC1271.
    /// Otherwise, the signature is validated with `ECDSA.recover`.
    function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits of `signer` in case they are dirty.
            for { signer := shr(96, shl(96, signer)) } signer {} {
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                if eq(mload(signature), 64) {
                    let vs := mload(add(signature, 0x40))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                    let t :=
                        staticcall(
                            gas(), // Amount of gas left for the transaction.
                            1, // Address of `ecrecover`.
                            0x00, // Start of input.
                            0x80, // Size of input.
                            0x01, // Start of output.
                            0x20 // Size of output.
                        )
                    // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                    if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                        isValid := 1
                        mstore(0x60, 0) // Restore the zero slot.
                        mstore(0x40, m) // Restore the free memory pointer.
                        break
                    }
                }
                if eq(mload(signature), 65) {
                    mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                    mstore(0x60, mload(add(signature, 0x40))) // `s`.
                    let t :=
                        staticcall(
                            gas(), // Amount of gas left for the transaction.
                            1, // Address of `ecrecover`.
                            0x00, // Start of input.
                            0x80, // Size of input.
                            0x01, // Start of output.
                            0x20 // Size of output.
                        )
                    // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                    if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                        isValid := 1
                        mstore(0x60, 0) // Restore the zero slot.
                        mstore(0x40, m) // Restore the free memory pointer.
                        break
                    }
                }
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.

                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                // Copy the `signature` over.
                let n := add(0x20, mload(signature))
                pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n))
                // forgefmt: disable-next-item
                isValid := and(
                    // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                    eq(mload(d), f),
                    // Whether the staticcall does not revert.
                    // This must be placed at the end of the `and` clause,
                    // as the arguments are evaluated from right to left.
                    staticcall(
                        gas(), // Remaining gas.
                        signer, // The `signer` address.
                        m, // Offset of calldata in memory.
                        add(returndatasize(), 0x44), // Length of calldata in memory.
                        d, // Offset of returndata.
                        0x20 // Length of returndata to write.
                    )
                )
                break
            }
        }
    }

    /// @dev Returns whether `signature` is valid for `signer` and `hash`.
    /// If `signer` is a smart contract, the signature is validated with ERC1271.
    /// Otherwise, the signature is validated with `ECDSA.recover`.
    function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits of `signer` in case they are dirty.
            for { signer := shr(96, shl(96, signer)) } signer {} {
                let m := mload(0x40)
                mstore(0x00, hash)
                if eq(signature.length, 64) {
                    let vs := calldataload(add(signature.offset, 0x20))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x40, calldataload(signature.offset)) // `r`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                    let t :=
                        staticcall(
                            gas(), // Amount of gas left for the transaction.
                            1, // Address of `ecrecover`.
                            0x00, // Start of input.
                            0x80, // Size of input.
                            0x01, // Start of output.
                            0x20 // Size of output.
                        )
                    // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                    if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                        isValid := 1
                        mstore(0x60, 0) // Restore the zero slot.
                        mstore(0x40, m) // Restore the free memory pointer.
                        break
                    }
                }
                if eq(signature.length, 65) {
                    mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                    calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`.
                    let t :=
                        staticcall(
                            gas(), // Amount of gas left for the transaction.
                            1, // Address of `ecrecover`.
                            0x00, // Start of input.
                            0x80, // Size of input.
                            0x01, // Start of output.
                            0x20 // Size of output.
                        )
                    // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                    if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                        isValid := 1
                        mstore(0x60, 0) // Restore the zero slot.
                        mstore(0x40, m) // Restore the free memory pointer.
                        break
                    }
                }
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.

                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), signature.length)
                // Copy the `signature` over.
                calldatacopy(add(m, 0x64), signature.offset, signature.length)
                // forgefmt: disable-next-item
                isValid := and(
                    // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                    eq(mload(d), f),
                    // Whether the staticcall does not revert.
                    // This must be placed at the end of the `and` clause,
                    // as the arguments are evaluated from right to left.
                    staticcall(
                        gas(), // Remaining gas.
                        signer, // The `signer` address.
                        m, // Offset of calldata in memory.
                        add(signature.length, 0x64), // Length of calldata in memory.
                        d, // Offset of returndata.
                        0x20 // Length of returndata to write.
                    )
                )
                break
            }
        }
    }

    /// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`.
    /// If `signer` is a smart contract, the signature is validated with ERC1271.
    /// Otherwise, the signature is validated with `ECDSA.recover`.
    function isValidSignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits of `signer` in case they are dirty.
            for { signer := shr(96, shl(96, signer)) } signer {} {
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x20, add(shr(255, vs), 27)) // `v`.
                mstore(0x40, r) // `r`.
                mstore(0x60, shr(1, shl(1, vs))) // `s`.
                let t :=
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        1, // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                    isValid := 1
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }

                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), 65) // Length of the signature.
                mstore(add(m, 0x64), r) // `r`.
                mstore(add(m, 0x84), mload(0x60)) // `s`.
                mstore8(add(m, 0xa4), mload(0x20)) // `v`.
                // forgefmt: disable-next-item
                isValid := and(
                    // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                    eq(mload(d), f),
                    // Whether the staticcall does not revert.
                    // This must be placed at the end of the `and` clause,
                    // as the arguments are evaluated from right to left.
                    staticcall(
                        gas(), // Remaining gas.
                        signer, // The `signer` address.
                        m, // Offset of calldata in memory.
                        0xa5, // Length of calldata in memory.
                        d, // Offset of returndata.
                        0x20 // Length of returndata to write.
                    )
                )
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

    /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`.
    /// If `signer` is a smart contract, the signature is validated with ERC1271.
    /// Otherwise, the signature is validated with `ECDSA.recover`.
    function isValidSignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits of `signer` in case they are dirty.
            for { signer := shr(96, shl(96, signer)) } signer {} {
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x20, and(v, 0xff)) // `v`.
                mstore(0x40, r) // `r`.
                mstore(0x60, s) // `s`.
                let t :=
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        1, // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                    isValid := 1
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }

                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), 65) // Length of the signature.
                mstore(add(m, 0x64), r) // `r`.
                mstore(add(m, 0x84), s) // `s`.
                mstore8(add(m, 0xa4), v) // `v`.
                // forgefmt: disable-next-item
                isValid := and(
                    // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                    eq(mload(d), f),
                    // Whether the staticcall does not revert.
                    // This must be placed at the end of the `and` clause,
                    // as the arguments are evaluated from right to left.
                    staticcall(
                        gas(), // Remaining gas.
                        signer, // The `signer` address.
                        m, // Offset of calldata in memory.
                        0xa5, // Length of calldata in memory.
                        d, // Offset of returndata.
                        0x20 // Length of returndata to write.
                    )
                )
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

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

    // Note: These ERC1271 operations do NOT have an ECDSA fallback.
    // These functions are intended to be used with the regular `isValidSignatureNow` functions
    // or other signature verification functions (e.g. P256).

    /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            // Copy the `signature` over.
            let n := add(0x20, mload(signature))
            pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n))
            // forgefmt: disable-next-item
            isValid := and(
                // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                eq(mload(d), f),
                // Whether the staticcall does not revert.
                // This must be placed at the end of the `and` clause,
                // as the arguments are evaluated from right to left.
                staticcall(
                    gas(), // Remaining gas.
                    signer, // The `signer` address.
                    m, // Offset of calldata in memory.
                    add(returndatasize(), 0x44), // Length of calldata in memory.
                    d, // Offset of returndata.
                    0x20 // Length of returndata to write.
                )
            )
        }
    }

    /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNowCalldata(
        address signer,
        bytes32 hash,
        bytes calldata signature
    ) internal view returns (bool isValid) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), signature.length)
            // Copy the `signature` over.
            calldatacopy(add(m, 0x64), signature.offset, signature.length)
            // forgefmt: disable-next-item
            isValid := and(
                // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                eq(mload(d), f),
                // Whether the staticcall does not revert.
                // This must be placed at the end of the `and` clause,
                // as the arguments are evaluated from right to left.
                staticcall(
                    gas(), // Remaining gas.
                    signer, // The `signer` address.
                    m, // Offset of calldata in memory.
                    add(signature.length, 0x64), // Length of calldata in memory.
                    d, // Offset of returndata.
                    0x20 // Length of returndata to write.
                )
            )
        }
    }

    /// @dev Returns whether the signature (`r`, `vs`) is valid for `hash`
    /// for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), 65) // Length of the signature.
            mstore(add(m, 0x64), r) // `r`.
            mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.
            mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.
            // forgefmt: disable-next-item
            isValid := and(
                // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                eq(mload(d), f),
                // Whether the staticcall does not revert.
                // This must be placed at the end of the `and` clause,
                // as the arguments are evaluated from right to left.
                staticcall(
                    gas(), // Remaining gas.
                    signer, // The `signer` address.
                    m, // Offset of calldata in memory.
                    0xa5, // Length of calldata in memory.
                    d, // Offset of returndata.
                    0x20 // Length of returndata to write.
                )
            )
        }
    }

    /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash`
    /// for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), 65) // Length of the signature.
            mstore(add(m, 0x64), r) // `r`.
            mstore(add(m, 0x84), s) // `s`.
            mstore8(add(m, 0xa4), v) // `v`.
            // forgefmt: disable-next-item
            isValid := and(
                // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                eq(mload(d), f),
                // Whether the staticcall does not revert.
                // This must be placed at the end of the `and` clause,
                // as the arguments are evaluated from right to left.
                staticcall(
                    gas(), // Remaining gas.
                    signer, // The `signer` address.
                    m, // Offset of calldata in memory.
                    0xa5, // Length of calldata in memory.
                    d, // Offset of returndata.
                    0x20 // Length of returndata to write.
                )
            )
        }
    }

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

    // Note: These ERC6492 operations do NOT have an ECDSA fallback.
    // These functions are intended to be used with the regular `isValidSignatureNow` functions
    // or other signature verification functions (e.g. P256).
    // The calldata variants are excluded for brevity.

    /// @dev Returns whether `signature` is valid for `hash`.
    /// If the signature is postfixed with the ERC6492 magic number, it will attempt to
    /// deploy / prepare the `signer` smart account before doing a regular ERC1271 check.
    /// Note: This function is NOT reentrancy safe.
    function isValidERC6492SignatureNowAllowSideEffects(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal returns (bool isValid) {
        /// @solidity memory-safe-assembly
        assembly {
            function callIsValidSignature(signer_, hash_, signature_) -> _isValid {
                let m_ := mload(0x40)
                let f_ := shl(224, 0x1626ba7e)
                mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m_, 0x04), hash_)
                let d_ := add(m_, 0x24)
                mstore(d_, 0x40) // The offset of the `signature` in the calldata.
                let n_ := add(0x20, mload(signature_))
                pop(staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_))
                _isValid :=
                    and(
                        eq(mload(d_), f_),
                        staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20)
                    )
            }
            for { let n := mload(signature) } 1 {} {
                if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) {
                    isValid := callIsValidSignature(signer, hash, signature)
                    break
                }
                let o := add(signature, 0x20) // Signature bytes.
                let d := add(o, mload(add(o, 0x20))) // Factory calldata.
                if iszero(extcodesize(signer)) {
                    if iszero(call(gas(), mload(o), 0, add(d, 0x20), mload(d), codesize(), 0x00)) {
                        break
                    }
                }
                let s := add(o, mload(add(o, 0x40))) // Inner signature.
                isValid := callIsValidSignature(signer, hash, s)
                if iszero(isValid) {
                    if call(gas(), mload(o), 0, add(d, 0x20), mload(d), codesize(), 0x00) {
                        isValid := callIsValidSignature(signer, hash, s)
                    }
                }
                break
            }
        }
    }

    /// @dev Returns whether `signature` is valid for `hash`.
    /// If the signature is postfixed with the ERC6492 magic number, it will attempt
    /// to use a reverting verifier to deploy / prepare the `signer` smart account
    /// and do a `isValidSignature` check via the reverting verifier.
    /// Note: This function is reentrancy safe.
    /// The reverting verifier must be be deployed.
    /// Otherwise, the function will return false if `signer` is not yet deployed / prepared.
    /// See: https://gist.github.com/Vectorized/846a474c855eee9e441506676800a9ad
    function isValidERC6492SignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            function callIsValidSignature(signer_, hash_, signature_) -> _isValid {
                let m_ := mload(0x40)
                let f_ := shl(224, 0x1626ba7e)
                mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m_, 0x04), hash_)
                let d_ := add(m_, 0x24)
                mstore(d_, 0x40) // The offset of the `signature` in the calldata.
                let n_ := add(0x20, mload(signature_))
                pop(staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_))
                _isValid :=
                    and(
                        eq(mload(d_), f_),
                        staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20)
                    )
            }
            for { let n := mload(signature) } 1 {} {
                if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) {
                    isValid := callIsValidSignature(signer, hash, signature)
                    break
                }
                if extcodesize(signer) {
                    let o := add(signature, 0x20) // Signature bytes.
                    isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40))))
                    if isValid { break }
                }
                let m := mload(0x40)
                mstore(m, signer)
                mstore(add(m, 0x20), hash)
                let willBeZeroIfRevertingVerifierExists :=
                    call(
                        gas(), // Remaining gas.
                        0x00007bd799e4A591FeA53f8A8a3E9f931626Ba7e, // Reverting verifier.
                        0, // Send zero ETH.
                        m, // Start of memory.
                        add(returndatasize(), 0x40), // Length of calldata in memory.
                        staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1.
                        0x00 // Length of returndata to write.
                    )
                isValid := gt(returndatasize(), willBeZeroIfRevertingVerifierExists)
                break
            }
        }
    }

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

    /// @dev Returns an Ethereum Signed Message, created from a `hash`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, hash) // Store into scratch space for keccak256.
            mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
            result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
        }
    }

    /// @dev Returns an Ethereum Signed Message, created from `s`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    /// Note: Supports lengths of `s` up to 999999 bytes.
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let sLength := mload(s)
            let o := 0x20
            mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
            mstore(0x00, 0x00)
            // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
            for { let temp := sLength } 1 {} {
                o := sub(o, 1)
                mstore8(o, add(48, mod(temp, 10)))
                temp := div(temp, 10)
                if iszero(temp) { break }
            }
            let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
            // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
            mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
            result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
            mstore(s, sLength) // Restore the length.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   EMPTY CALLDATA HELPERS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an empty calldata bytes.
    function emptySignature() internal pure returns (bytes calldata signature) {
        /// @solidity memory-safe-assembly
        assembly {
            signature.length := 0
        }
    }
}

File 6 of 9 : IRebootTournament.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.28;

interface IRebootTournament {
    struct Entry {
        uint256 ticketBasedCollateral;
        uint256 creditBasedCollateral;
        uint256 totalCollateralPaid;
        uint248 rebuyCount;
        bool payoutReceived;
    }

    struct Result {
        address player;
        uint256 multiplier;
    }

    struct EntryParams {
        address account;
        uint256 tournamentId;
        uint256 roomId;
        address swapFromCredit;
        uint256 swapMinCollateral;
        uint256 entryAmount;
    }

    struct Config {
        uint256 entryFee; // credit fee to enter tournament (new entry for a new score)
        uint256 rebuyFee; // credit fee to rebuy into tournament (re-attempt an existing entry to try to improve score)
        bool isExactFee; // if true, above fees are exact required fees. if false, above fees are minimum fees
        uint64 entryLimit; // max number of entries allowed per player
        uint64 maxEntriesPerRoom; // max number of entries allowed per room
        uint64 rebuyLimit; // max number of rebuys allowed per player per entry
        uint64 startDate; // start date of tournament (block timestamp)
        uint64 endDate; // end date of tournament (block timestamp)
        uint64 ticketProfitToTickets; // % of profit from ticket entry converted to ticket payout (in wei)
        uint64 creditProfitToTickets; // % of profit from credit entry converted to credit payout (in wei)
        uint64 creditEntryToTickets; // % of credit entry converted to ticket payout (in wei)
        uint64 entryDuration; // duration in seconds of entry period for a room once the room is opened
        uint64 tournamentDuration; // duration in seconds of tournament instance (room) once started
        uint64 payoutDuration; // duration in seconds to allow payouts for after tournament ends
        uint96 creditRatio; // ratio of collateral to credits (gets set during register transaction)
        address creditId; // credit id to use for entry fee (the id is the collateral token address)
        uint256 bonusCollateral; // amount of collateral to request each time it's needed
        bytes32 priceFeedPair; // pair to use for price feed (use bytes32(0) for a flat credit fee)
    }

    // Tournament IDs
    function tournamentCount() external view returns (uint256);

    // Allowed to set contract configs and register tournaments
    function ADMIN_ROLE() external view returns (bytes32);

    // Allowed to call `enter`, `rebuy` and `submitResults`
    function RELAYER_ROLE() external view returns (bytes32);

    /**
     * @notice Get the tournament config set by contract admin
     *
     * @param _tournamentId ID of the tournament
     */
    function getTournament(uint256 _tournamentId) external view returns (Config memory);

    /**
     * @notice Opens a new room for an active tournament
     *
     * @param _tournamentId ID of the tournament
     * @param _roomId ID of the tournament room
     * @param _openTimestamp Timestamp to open the room
     */
    function createRoom(uint256 _tournamentId, uint256 _roomId, uint64 _openTimestamp) external;

    /**
     * @notice Enters a player into a tournament room. If the room does not exist, it will be created.
     *
     * @dev A player can only enter a specific room once.
     *
     * @param _params entry params struct
     */
    function enter(EntryParams calldata _params) external payable;

    /**
     * @notice Allows a player to rebuy into a tournament room for a chance to improve their score
     *
     * @param _tournamentId ID of the tournament
     * @param _account Address of player
     * @param _roomId ID of the tournament room
     * @param _swapFromCredit credit token to swap from, use zero address if swap not wanted
     * @param _swapMinCollateral min amount of output collateral to receive from swap
     * @param _entryAmount credit amount to spend to enter - if tournament config has `isExactFee` set to true, must be equivalent to `rebuyFee`. Otherwise, must be >= `rebuyFee`
     */
    function rebuy(
        uint256 _tournamentId,
        address _account,
        uint256 _roomId,
        address _swapFromCredit,
        uint256 _swapMinCollateral,
        uint256 _entryAmount
    ) external payable;

    /**
     * @notice Submits the results of a tournament room. Payouts are calculated and credits are minted to players.
     *
     * @param _tournamentId ID of the tournament
     * @param _roomId ID of the tournament room
     * @param _results Array of results for the room
     */
    function submitResults(uint256 _tournamentId, uint256 _roomId, Result[] memory _results) external;

    function credits() external view returns (address);

    /**
     * @notice Admin function to register a new tournament
     *
     * @param _c Config struct for the tournament
     */
    function register(Config memory _c) external returns (uint256 _tournamentId);

    /**
     * @notice Get the entry for a player in a room
     *
     * @param _tournamentId ID of the tournament
     * @param _player Address of the player
     * @param _roomId ID of the tournament room
     */
    function getEntry(uint256 _tournamentId, address _player, uint256 _roomId) external view returns (Entry memory);

    /**
     * @notice Cleans up a tournament room after the payout duration has ended. Returns any remaining collateral to the game dev or bonus contract.
     *
     * @param _tournamentId ID of the tournament
     * @param _roomId ID of the tournament room
     */
    function cleanup(uint256 _tournamentId, uint256 _roomId) external;
}

File 7 of 9 : TopTraderStructs.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.28;

enum Direction {
    LONG,
    SHORT
}

struct Trade {
    bytes32 pair;
    uint40 lastUpdatedAt;
    int104 entryPrice;
    int104 amountInBips;
}

struct InternalPrice {
    int64 price;
    int32 expo;
    uint40 publishTime;
}

struct TournamentConfig {
    uint16 minimumHoldDuration;
    uint16 maxLeverage;
    uint40 startTime;
    uint40 endTime;
    uint128 startBalance;
    mapping(bytes32 pair => InternalPrice finalPrice) finalPrices;
    mapping(address user => int256 balance) userBalance;
    mapping(address user => Trade trade) activeTrade;
}

File 8 of 9 : IPythEvents.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/// @title IPythEvents contains the events that Pyth contract emits.
/// @dev This interface can be used for listening to the updates for off-chain and testing purposes.
interface IPythEvents {
    /// @dev Emitted when the price feed with `id` has received a fresh update.
    /// @param id The Pyth Price Feed ID.
    /// @param publishTime Publish time of the given price update.
    /// @param price Price of the given price update.
    /// @param conf Confidence interval of the given price update.
    event PriceFeedUpdate(
        bytes32 indexed id,
        uint64 publishTime,
        int64 price,
        uint64 conf
    );

    /// @dev Emitted when a batch price update is processed successfully.
    /// @param chainId ID of the source chain that the batch price update comes from.
    /// @param sequenceNumber Sequence number of the batch price update.
    event BatchPriceFeedUpdate(uint16 chainId, uint64 sequenceNumber);
}

File 9 of 9 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /// @dev Cannot double-initialize.
    error AlreadyInitialized();

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

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

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

    /// @dev The owner slot is given by:
    /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    bytes32 internal constant _OWNER_SLOT =
        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                if sload(ownerSlot) {
                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
                    revert(0x1c, 0x04)
                }
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(_OWNER_SLOT, newOwner)
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, newOwner)
            }
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(_OWNER_SLOT))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_OWNER_SLOT)
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

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

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "solady/=lib/solady/src/",
    "pyth/=lib/pyth-sdk-solidity/",
    "NFTMIrror/=lib/NFTMIrror/src/",
    "pyth-sdk-solidity/=lib/pyth-sdk-solidity/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"pyth","type":"address"},{"internalType":"address","name":"reboot","type":"address"},{"internalType":"address","name":"wape","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"_liquidationBounty","type":"uint256"},{"internalType":"uint256","name":"_baseSlippage","type":"uint256"},{"internalType":"uint256","name":"_slippageIncrement","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyEntered","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[{"internalType":"int256","name":"balanceInBips","type":"int256"},{"internalType":"int256","name":"requiredAmountInBips","type":"int256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientEntryFee","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidPriceUpdates","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidTimestamp","type":"error"},{"inputs":[],"name":"LiquidationBountyTooHigh","type":"error"},{"inputs":[],"name":"MinTimestampNotMet","type":"error"},{"inputs":[],"name":"MinimumHoldDurationNotMet","type":"error"},{"inputs":[],"name":"MismatchedPairs","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NonceAlreadyUsed","type":"error"},{"inputs":[],"name":"NotActive","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[],"name":"SlippageTooHigh","type":"error"},{"inputs":[],"name":"StalePrice","type":"error"},{"inputs":[],"name":"TournamentActive","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tournamentId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"int256","name":"balance","type":"int256"},{"indexed":false,"internalType":"int256","name":"amount","type":"int256"},{"indexed":false,"internalType":"int256","name":"entryPrice","type":"int256"},{"indexed":false,"internalType":"bytes32","name":"pair","type":"bytes32"}],"name":"AccountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFactor","type":"uint256"}],"name":"BaseSlippageScalingFactorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newSigner","type":"address"}],"name":"CounterpartySignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tournamentId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"int256","name":"balance","type":"int256"},{"indexed":false,"internalType":"int256","name":"pnl","type":"int256"}],"name":"InvalidLiquidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tournamentId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Liquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LiquidationBountyPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newBounty","type":"uint256"}],"name":"LiquidationBountyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFactor","type":"uint256"}],"name":"SlippageScalingFactorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tournamentId","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"pairs","type":"bytes32[]"},{"indexed":false,"internalType":"uint40","name":"startTime","type":"uint40"},{"indexed":false,"internalType":"uint40","name":"endTime","type":"uint40"},{"indexed":false,"internalType":"uint128","name":"startBalance","type":"uint128"},{"indexed":false,"internalType":"uint16","name":"maxLeverage","type":"uint16"},{"indexed":false,"internalType":"uint80","name":"entryFee","type":"uint80"},{"indexed":false,"internalType":"uint16","name":"minimumHoldDuration","type":"uint16"},{"indexed":false,"internalType":"uint64","name":"rebuyLimit","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"bonusCollateral","type":"uint256"}],"name":"TournamentCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tournamentId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"int256","name":"amount","type":"int256"},{"indexed":false,"internalType":"int256","name":"executionPrice","type":"int256"},{"indexed":false,"internalType":"bytes32","name":"pair","type":"bytes32"}],"name":"TradeExecuted","type":"event"},{"inputs":[],"name":"SIGNATURE_VALIDITY_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"activeTrade","outputs":[{"components":[{"internalType":"bytes32","name":"pair","type":"bytes32"},{"internalType":"uint40","name":"lastUpdatedAt","type":"uint40"},{"internalType":"int104","name":"entryPrice","type":"int104"},{"internalType":"int104","name":"amountInBips","type":"int104"}],"internalType":"struct Trade","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseSlippageScalingFactor","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"}],"name":"cleanup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"counterpartySigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"pairs","type":"bytes32[]"},{"internalType":"uint16","name":"minimumHoldDuration","type":"uint16"},{"internalType":"uint40","name":"startTime","type":"uint40"},{"internalType":"uint40","name":"endTime","type":"uint40"},{"internalType":"uint128","name":"startBalance","type":"uint128"},{"internalType":"uint16","name":"maxLeverage","type":"uint16"},{"internalType":"uint80","name":"entryFee","type":"uint80"},{"internalType":"uint64","name":"rebuyLimit","type":"uint64"},{"internalType":"uint256","name":"bonusCollateral","type":"uint256"}],"name":"createTournament","outputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"currentPnlFor","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentTournamentId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"}],"name":"enterTournament","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"tournamentId","type":"uint256"}],"name":"enterTournamentFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"bytes32","name":"pair","type":"bytes32"}],"name":"finalPrice","outputs":[{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint40","name":"publishTime","type":"uint40"}],"internalType":"struct InternalPrice","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"bytes[]","name":"priceUpdates","type":"bytes[]"},{"internalType":"bytes32[]","name":"pairs","type":"bytes32[]"}],"name":"finalizePrices","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"pair","type":"bytes32"}],"name":"internalPrices","outputs":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint40","name":"publishTime","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"bytes[]","name":"priceUpdates","type":"bytes[]"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidationBounty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"factor","type":"uint256"}],"name":"setBaseSlippageScalingFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"setCounterpartySigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bounty","type":"uint256"}],"name":"setLiquidationBounty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"factor","type":"uint256"}],"name":"setSlippageIncrementScalingFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"slippageIncrementScalingFactor","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"components":[{"internalType":"address","name":"player","type":"address"},{"internalType":"uint256","name":"multiplier","type":"uint256"}],"internalType":"struct IRebootTournament.Result[]","name":"results","type":"tuple[]"}],"name":"submitResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"}],"name":"tournaments","outputs":[{"internalType":"uint16","name":"minimumHoldDuration","type":"uint16"},{"internalType":"uint16","name":"maxLeverage","type":"uint16"},{"internalType":"uint40","name":"startTime","type":"uint40"},{"internalType":"uint40","name":"endTime","type":"uint40"},{"internalType":"uint128","name":"startBalance","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"bytes32","name":"pair","type":"bytes32"},{"internalType":"bytes[]","name":"priceUpdates","type":"bytes[]"},{"internalType":"int256","name":"amountInBips","type":"int256"},{"internalType":"address","name":"trader","type":"address"},{"internalType":"uint256","name":"minTimestamp","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"trade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"pairs","type":"bytes32[]"},{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint40","name":"publishTime","type":"uint40"}],"internalType":"struct InternalPrice[]","name":"prices","type":"tuple[]"}],"name":"updateManualPriceFeeds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"priceUpdates","type":"bytes[]"}],"name":"updatePythPriceFeeds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"usedNonces","outputs":[{"internalType":"bool","name":"isUsed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"userBalance","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e03461029357601f61353038819003918201601f19168301916001600160401b038311848410176102985780849260e09460405283398101031261029357610047816102ae565b90610054602082016102ae565b610060604083016102ae565b9061006d606084016102ae565b9160808401519160c060a08601519501519560018060a01b031680158015610282575b8015610271575b6102605732638b78c6d819553260007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3638b78c6d8600c52326000526020600c2068200000040000000000815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a36080526001600160a01b0390811660a05260c09190915260019190915516801561026057600080546001600160a01b031916821790556040519081527f433d5aa4c8f989b56375c20361c91cb7dca10cebc7e123572fa796421e85251e90602090a160fa811161024f576020817fd7bf6fb5afa6dde675c1b0e83381bb3d5dc5a0f4711c590e63a0a4ec6494395e92600255604051908152a1600a811161024f576020817f3fff8b1775def0fb5bb8d5be4d00c6de3f320bd44db6653469073a7ded6ddb6992600355604051908152a160405161326d90816102c382396080518181816104d60152818161263c01528181612dee0152612ec7015260a0518181816102460152818161085901528181610c8c01528181610cbf01528181610d1d01528181612175015261292f015260c05181610afc0152f35b63428637bb60e11b60005260046000fd5b63d92e233d60e01b60005260046000fd5b506001600160a01b03831615610097565b506001600160a01b03821615610090565b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036102935756fe6080604052600436101561001b575b361561001957600080fd5b005b6000803560e01c8063032e9c761461240a5780630989e8df146121f55780630aa4001814612158578063183a4f6e1461213f57806318d913bd1461212157806319a4edb1146120615780631c10893f14611fff5780631cd64df414611fc557806323a1625614611fa95780632569296214611f5e57806326097b5a14611f3d5780632de9480714611f0a57806330a4d88114611eb35780633ccfd60b14611e725780633d46f265146114885780634a4ee7b11461145f5780634d22beb3146114385780634e609e32146113d2578063514e62fc1461139957806354343c551461118257806354d1f13d1461113c5780636717e41c1461110d5780636e5f7d06146110ef578063715018a6146110a45780637503e1b7146110365780637ed3a26414610fc85780638519870514610f7e5780638da5cb5b14610f515780638efaaea914610f08578063b26c24bc14610956578063b2bedf2314610938578063b4e517f6146107fe578063b965cc6b146107c4578063d4f9365814610484578063dcfb21ed14610405578063e2a399e5146103ec578063f04e283e1461039e578063f2fde38b1461035f578063f4277a7e146102cc578063fc8e75041461021f5763fee81cf4146101ea575061000e565b3461021c57602036600319011261021c5761020361248a565b9063389a75e1600c5252602080600c2054604051908152f35b80fd5b503461021c578060031936011261021c57604051631b8acb1f60e21b8152906020826004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156102c05790610288575b602090604051908152f35b506020813d6020116102b8575b816102a26020938361255d565b810103126102b3576020905161027d565b600080fd5b3d9150610295565b604051903d90823e3d90fd5b503461021c57604036600319011261021c576040816060928280516102f0816124f5565b82815282602082015201526004358152600460205260018282200160243582526020522064ffffffffff60405191610327836124f5565b548060070b92838152826040602083019284821c60030b84520192861c1682526040519384525160030b602084015251166040820152f35b50602036600319011261021c5761037461248a565b61037c6128dc565b8060601b156103915761038e9061312e565b80f35b637448fbae82526004601cfd5b50602036600319011261021c576103b361248a565b6103bb6128dc565b63389a75e1600c528082526020600c20805442116103df57908261038e925561312e565b636f5e881883526004601cfd5b50602036600319011261021c5761038e600435336128eb565b503461021c57602036600319011261021c5761041f61248a565b6104276128bb565b6001600160a01b031680156104755781546001600160a01b031916811782556040519081527f433d5aa4c8f989b56375c20361c91cb7dca10cebc7e123572fa796421e85251e90602090a180f35b63d92e233d60e01b8252600482fd5b503461021c57610493366124a0565b92909361049e612889565b85526004602052604085209364ffffffffff855460481c16924284116107b55760405163d47eed4560e01b81526020600482018190527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031695919390848061051260248201878a61257e565b0381895afa9384156107aa578994610776575b5060058201906001600160401b03821161076257916001600160401b036105749694926105868c9997956040519b8c9a8b998a98634716e9c560e01b8a52608060048b015260848a019161257e565b878103600319016024890152916127e5565b92604485015216606483015203925af190811561075757839161065b575b5090600101825b8251811015610657578060206105c360019386612875565b510151805160070b9064ffffffffff6060604083015160030b92015116604051926105ed846124f5565b835260208301918252604083019081526106078488612875565b5151885285602052604088209251916001600160401b038454915160401b9264ffffffffff60601b905160601b169316906001600160881b031916179063ffffffff60401b1617179055016105ab565b8380f35b90503d8084833e61066c818361255d565b81019060208183031261074f578051906001600160401b038211610753570181601f8201121561074f578051906001600160401b03821161073b57604051926106bb60208460051b018561255d565b828452602061012081860194028301019181831161073757602001925b8284106106e95750505050386105a4565b6101208483031261073757602061012091604051610706816124f5565b865181526107168584890161281d565b838201526107278560a0890161281d565b60408201528152019301926106d8565b8680fd5b634e487b7160e01b85526041600452602485fd5b8380fd5b8480fd5b6040513d85823e3d90fd5b634e487b7160e01b8a52601160045260248afd5b9093506020813d6020116107a2575b816107926020938361255d565b810103126102b357519238610525565b3d9150610785565b6040513d8b823e3d90fd5b634a65fe1160e01b8752600487fd5b503461021c57604036600319011261021c576107f660209160406107e6612474565b916004358152600485522061303c565b604051908152f35b503461021c57604036600319011261021c57602435906001600160401b03821161021c573660238301121561021c5781600401356001600160401b038111610934573660248260061b8501011161093457610857612889565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692833b156109305760405191639eed5e2160e01b835280606484016004356004860152856024860152606060448601525260246084840192019084905b8082106108fd57505050818394818581819503925af180156108f2576108e15750f35b816108eb9161255d565b61021c5780f35b6040513d84823e3d90fd5b909192833560018060a01b03811680910361073757604082819260019452602087013560208201520194019201906108be565b8280fd5b5080fd5b503461021c578060031936011261021c576020600354604051908152f35b503461021c5761012036600319011261021c576004356001600160401b03811161093457610988903690600401612444565b906024359161ffff8316830361074f5760443564ffffffffff81168103610753576064359364ffffffffff85168503610f04576001600160801b036084351660843503610f045760a4359061ffff821682036107375760c43569ffffffffffffffffffff81168103610f005760e435926001600160401b0384168403610efc57610a10612889565b64ffffffffff808616818a160311610ee85760405197610a2f89612541565b69ffffffffffffffffffff8316895269ffffffffffffffffffff831660208a0152600160408a01526001600160401b0360608a01526001600160401b0360808a01526001600160401b03851660a08a015264ffffffffff861660c08a015264ffffffffff811660e08a0152670de0b6b3a76400006101008a0152670de0b6b3a76400006101208a0152670de0b6b3a76400006101408a015264ffffffffff80871681831603166101608a0152896101808a015262278d006101a08a0152896101c08a015260018060a01b037f0000000000000000000000000000000000000000000000000000000000000000166101e08a0152610104356102008a0152896102208a0152610220604051996328889c6d60e21b8b52805160048c0152602081015160248c01526040810151151560448c01526001600160401b0360608201511660648c01526001600160401b0360808201511660848c01526001600160401b0360a08201511660a48c01526001600160401b0360c08201511660c48c01526001600160401b0360e08201511660e48c01526001600160401b03610100820151166101048c01526001600160401b03610120820151166101248c01526001600160401b03610140820151166101448c01526001600160401b03610160820151166101648c01526001600160401b03610180820151166101848c01526001600160401b036101a0820151166101a48c01526001600160601b036101c0820151166101c48c015260018060a01b036101e0820151166101e48c01526102008101516102048c015201516102248a0152602089610244818d60018060a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1988915610edd578a99610ea9575b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163b15610e9a57604051637aac643f60e01b8152600481018a9052602481018b905264ffffffffff871660448201528a81606481837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015610e9e57610e85575b508989809b5260046020526040902080548360101b63ffff0000169063ffff000019906001600160801b0360701b199061ffff8916906dffffffffffffffffffff0000ffff191617168960201b68ffffffffff000000001617168360481b6dffffffffff00000000000000000016176001600160801b0360701b60843560701b16171790556040519788976101208952610120890190610df1926127e5565b9564ffffffffff16602088015264ffffffffff1660408701526084356001600160801b0316606087015261ffff16608086015269ffffffffffffffffffff1660a085015261ffff1660c08401526001600160401b031660e083015261010435610100830152037f07f0d15dca459300ceadf62f30ae8e6b90af800ea554cc7530cc837b96b5d50991a2604051908152602090f35b610e908b809261255d565b610e9a5738610d52565b8980fd5b6040513d8d823e3d90fd5b9098506020813d602011610ed5575b81610ec56020938361255d565b810103126102b357519738610cbc565b3d9150610eb8565b6040513d8c823e3d90fd5b634e487b7160e01b89526011600452602489fd5b8880fd5b8780fd5b8580fd5b503461021c57602036600319011261021c57604060609160043581526005602052205464ffffffffff604051918060070b83528060401c60030b6020840152831c166040820152f35b503461021c578060031936011261021c57638b78c6d819546040516001600160a01b039091168152602090f35b503461021c57604036600319011261021c5760026040610f9c612474565b926004358152600460205220019060018060a01b03166000526020526020604060002054604051908152f35b503461021c57602036600319011261021c57600435610fe56128bb565b683635c9adc5dea000008111611027576020817fa6635fc6998b0f79d9889a9d1cba35ab931d2e68ebe46f897c1fb915a5b874e492600155604051908152a180f35b63263d748960e11b8252600482fd5b503461021c57602036600319011261021c57604060a0916004358152600460205220546001600160801b036040519161ffff8116835261ffff8160101c16602084015264ffffffffff8160201c16604084015264ffffffffff8160481c16606084015260701c166080820152f35b508060031936011261021c576110b86128dc565b80638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380638b78c6d8195580f35b503461021c578060031936011261021c576020600154604051908152f35b503461021c57602036600319011261021c5760ff60406020926004358152600684522054166040519015158152f35b508060031936011261021c5763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b503461021c576111b5611194366124a0565b848796929394959652600460205260408720926111b084612c26565b612617565b8493859360028301925b848610611225578787806111d1575080f35b8180808084335af16111e1612740565b5015611216576040519081527f0b8af83edb58a3c0794e9aadbac8779b13e493370e536255cf3b1a7da9239d3e60203392a280f35b6312171d8360e31b8252600482fd5b90919293949561124761124161123c89898761271a565b6127d1565b8361303c565b604061125761123c8a8a8861271a565b6001600160a01b0316600090815260208890522054818101908a831280159183129182169115161761076257891315611326575060019088604061129f61123c8b8b8961271a565b600090858060a01b03168152886020522055888260406112c361123c8c8c8a61271a565b600090838060a01b031681526003870160205220828155015581540196818060a01b036112f461123c838a8861271a565b16857f03b910a1639200ab2b0061788a7e4d39f45a305c900ac7f92a77b9a8447df9dc8b80a35b0194939291906111bf565b9660019197857fdc57291b7b129d2079685e49dc1d00cea767d4f624f9523d658fd5ce90a6469660408a8161136e61123c8861136761123c828f889061271a565b948d61271a565b600090898060a01b031681528c60205220549482519586526020860152868060a01b031693a361131b565b503461021c57604036600319011261021c576113b361248a565b90638b78c6d8600c5252602060243581600c2054161515604051908152f35b503461021c57602036600319011261021c576004356113ef6128bb565b600a8111611429576020817f3fff8b1775def0fb5bb8d5be4d00c6de3f320bd44db6653469073a7ded6ddb6992600355604051908152a180f35b63428637bb60e11b8252600482fd5b503461021c578060031936011261021c57546040516001600160a01b039091168152602090f35b50604036600319011261021c5761038e61147761248a565b61147f6128dc565b6024359061316c565b503461021c5761010036600319011261021c576044356001600160401b038111610934576114ba903690600401612444565b608435906001600160a01b038216820361074f5760e435906001600160401b0382116107535736602383011215610753576001600160401b03826004013511610753573660248360040135840101116107535760643515611e635760a4354210611e5457601e60a435014211611e4557600435855260046020526040852061154181612c26565b60018060a01b038416600052600381016020526040600020916040519561156787612526565b6001845494858952015464ffffffffff811660208901528060281c600c0b60408901528060901c600c0b6060890152889480611dce575b505060c4358852600660205260ff604089205416611dc05760c4358852600660205260408820805460ff19166001179055606435881215611db85787945b6040516001600160601b03198860601b166020820152600435603482015260243560548201526002871015611da4578660f81b607482015260a435607582015260c43560958201526095815261163360b58261255d565b805160209182012090527b19457468657265756d205369676e6564204d6573736167653a0a33328952603c600420336001600160a01b03891603611d6d578954611691926004810135926024909101916001600160a01b0316612c68565b15611d5e57906116a091612617565b6116ab602435612d7c565b916116c98387906060906040830151600c0b9003910151600c0b0290565b90600283019460018060a01b03871660005285602052604060002054916116f660608a0151600c0b612f53565b916127108061ffff885460101c168782880201020581898602059084600014611d5857015b02611727606435612f53565b92888402918d8512600160ff1b8b1416611d44578483058a1485151715611d4457808313611d1e575015611bb557508183036118a157505050611817939495965060018060a01b03871660005285602052612710604060002092050190556040519061179282612526565b868252602082019164ffffffffff4216835264ffffffffff80600160408401938b8552600360608201968d8852838060a01b038d1660005201602052604060002090518155019451161664ffffffffff198454161783555182549060281b600160281b600160901b031690600160281b600160901b03191617825551600c0b9061279f565b6040805160643581526020810192909252602435908201526001600160a01b0383169060c435906004359060008051602061321883398151915290606090a460018060a01b038216600052602052604060002054906040519083825283602083015283604083015260018060a01b0316906000805160206131f8833981519152606060043592a480f35b939796959493828212156119cb57506118d560039493926127109260608c0151600c0b606435600c0b01600c0b9a0261277f565b050160018060a01b0386166000528460205260406000205560018060a01b03851660005281810160205261191086600160406000200161279f565b6001600160a01b0385166000818152919092016020908152604091829020600101805464ffffffffff421664ffffffffff199091161790558151606435815290810193909352602435908301529060c435906004359060008051602061321883398151915290606090a460018060a01b03821660005260205260408060002054930151600c0b6040519283526020830152602435604083015260018060a01b0316906000805160206131f8833981519152606060043592a480f35b949396989150506060919682820151600c0b606435600c0b01600c0b9760018060a01b038a1660005286602052612710604060002092050190550151600c0b870380600c0b908103611ba15760408051600c9290920b82526020820183905260243590820152611b0a92611a729290916001600160a01b0389169060c435906004359060008051602061321883398151915290606090a4611a6d818802612f53565b612f83565b9260405190611a8082612526565b6024358252602082019164ffffffffff4216835264ffffffffff806001604084019389600c0b8552600360608201968c88528d848060a01b031660005201602052604060002090518155019451161664ffffffffff198454161783555182549060281b600160281b600160901b031690600160281b600160901b03191617825551600c0b9061279f565b60408051600c85900b815260208101849052602435918101919091526001600160a01b0385169060c435906004359060008051602061321883398151915290606090a46001600160a01b039390931660008181526020948552604090819020548151600c9590950b8552948401929092526024359183019190915290600435906000805160206131f883398151915290606090a480f35b634e487b7160e01b88526011600452602488fd5b611c8b9550611bf9945096611bd092939698979a999a612f83565b938181604060608b0151600c0b606435600c0b01600c0b9a0151600c0b0291019185020161277f565b93858764ffffffffff806001604051611c1181612526565b602435815260036020820197844216895260408301968d600c0b885260608401988952848060a01b031660005201602052604060002090518155019451161664ffffffffff198454161783555182549060281b600160281b600160901b031690600160281b600160901b03191617825551600c0b9061279f565b6040805160643581526020810192909252602435908201526001600160a01b0385169060c435906004359060008051602061321883398151915290606090a46001600160a01b039390931660008181526020948552604090819020548151600c9590950b8552948401929092526024359183019190915290600435906000805160206131f883398151915290606090a480f35b8d83828260449412611d3d575b63e3f3d0e360e01b8352600452602452fd5b5081611d2b565b634e487b7160e01b8e52601160045260248efd5b0361171b565b638baa579f60e01b8852600488fd5b8954336001600160a01b0390911603611d955790611691916024826004013592019089612c68565b6348f5c3ed60e01b8a5260048afd5b634e487b7160e01b8a52602160045260248afd5b6001946115dc565b623f613760e71b8852600488fd5b60243514611de557630631dbcd60e11b8952600489fd5b8860643513898260901c600c0b1303611e01575b50388061159e565b90935064ffffffffff61ffff84541691160164ffffffffff8111611ba15764ffffffffff42911611611e365760019238611df9565b633e7c0cc760e11b8752600487fd5b630819bdcd60e01b8552600485fd5b631abad6d560e11b8552600485fd5b63162908e360e11b8552600485fd5b503461021c578060031936011261021c57611e8b6128dc565b8080808047335af1611e9b612740565b5015611ea45780f35b6312171d8360e31b8152600490fd5b503461021c57602036600319011261021c57600435611ed06128bb565b60fa8111611429576020817fd7bf6fb5afa6dde675c1b0e83381bb3d5dc5a0f4711c590e63a0a4ec6494395e92600255604051908152a180f35b503461021c57602036600319011261021c57611f2461248a565b90638b78c6d8600c5252602080600c2054604051908152f35b50604036600319011261021c5761038e611f5561248a565b602435906128eb565b508060031936011261021c5763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b503461021c578060031936011261021c576020604051601e8152f35b503461021c57604036600319011261021c57602090611fe261248a565b60243591638b78c6d8600c52528082600c20541614604051908152f35b50604036600319011261021c5761201461248a565b61201c6128dc565b638b78c6d8600c5281526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe268380a380f35b503461021c57604036600319011261021c576003604061207f612474565b92806060835161208e81612526565b828152826020820152828582015201526004358152600460205220019060018060a01b0316600052602052608060406000206040516120cc81612526565b600182549283835201549064ffffffffff602082018184168152606060408401938560281c600c0b8552019360901c600c0b84526040519485525116602084015251600c0b604083015251600c0b6060820152f35b503461021c578060031936011261021c576020600254604051908152f35b50602036600319011261021c5761038e6004353361316c565b503461021c57602036600319011261021c57612172612889565b807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156121f257818091604460405180958193633d1a69db60e21b835260043560048401528160248401525af180156121e5576121d75780f35b6121e09161255d565b388180f35b50604051903d90823e3d90fd5b50fd5b503461021c57604036600319011261021c576004356001600160401b03811161093457612226903690600401612444565b602435916001600160401b03831161074f573660238401121561074f578260040135926001600160401b03841161075357366024606086028301011161075357638b78c6d8600c52338552600160581b6020600c205416156123fd578383036123ee57845b838110612296578580f35b848110156123da576060810282016060602319823603011261073757604051906122bf826124f5565b60248101358060070b8103610efc5782526044810135908160030b8203610efc57602083019182526064013564ffffffffff81168103610efc576040830190815261230b84888861271a565b3560016242006960e01b03196001600160e01b03198216016123cb574264ffffffffff835116116123bc579060019493929164ffffffffff825116818c52600560205264ffffffffff60408d205460601c1610156123b3578a52600560205260408a209251916001600160401b038454915160401b9264ffffffffff60601b905160601b169316906001600160881b031916179063ffffffff60401b16171790555b0161228b565b505050506123ad565b63b7d0949760e01b8a5260048afd5b631bd2d0af60e01b8a5260048afd5b634e487b7160e01b86526032600452602486fd5b63512509d360e11b8552600485fd5b6382b4290085526004601cfd5b503461021c57602036600319011261021c576004356001600160401b0381116109345761243e61038e913690600401612444565b90612617565b9181601f840112156102b3578235916001600160401b0383116102b3576020808501948460051b0101116102b357565b602435906001600160a01b03821682036102b357565b600435906001600160a01b03821682036102b357565b9060606003198301126102b357600435916024356001600160401b0381116102b357816124cf91600401612444565b92909291604435906001600160401b0382116102b3576124f191600401612444565b9091565b606081019081106001600160401b0382111761251057604052565b634e487b7160e01b600052604160045260246000fd5b608081019081106001600160401b0382111761251057604052565b61024081019081106001600160401b0382111761251057604052565b90601f801991011681019081106001600160401b0382111761251057604052565b90602083828152019060208160051b85010193836000915b8383106125a65750505050505090565b909192939495601f198282030186528635601e19843603018112156102b357830190602082359201916001600160401b0381116102b35780360383136102b3576020828280600196849695859652848401376000828201840152601f01601f19160101980196019493019190612596565b6000918061262457505050565b60405163d47eed4560e01b81526020600482018190527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316929190818061267760248201868961257e565b0381865afa90811561270f5785916126dd575b50823b1561075357916126be93918593604051809681958294631df3cbc560e31b845260206004850152602484019161257e565b03925af180156108f2576126d0575050565b816126da9161255d565b50565b90506020813d602011612707575b816126f86020938361255d565b8101031261075357513861268a565b3d91506126eb565b6040513d87823e3d90fd5b919081101561272a5760051b0190565b634e487b7160e01b600052603260045260246000fd5b3d1561277a573d906001600160401b038211612510576040519161276e601f8201601f19166020018461255d565b82523d6000602084013e565b606090565b8115612789570590565b634e487b7160e01b600052601260045260246000fd5b9081549060901b6cffffffffffffffffffffffffff60901b16906cffffffffffffffffffffffffff60901b1916179055565b356001600160a01b03811681036102b35790565b81835290916001600160fb1b0383116102b35760209260051b809284830137010190565b51906001600160401b03821682036102b357565b91908260809103126102b35760405161283581612526565b809280518060070b81036102b357825261285160208201612809565b602083015260408101518060030b81036102b3576040830152606090810151910152565b805182101561272a5760209160051b010190565b638b78c6d8600c5233600052682000000000000000006020600c205416156128ad57565b6382b429006000526004601cfd5b638b78c6d8600c5233600052650400000000006020600c205416156128ad57565b638b78c6d8195433036128ad57565b600082815260046020526040812090600282019260018060a01b0381168252836020526040822054612c175761292083612c26565b60015434039460018060a01b037f000000000000000000000000000000000000000000000000000000000000000016604051630696f5ff60e21b815282600482015261024081602481855afa90811561270f578591612a9f575b50516001600160a01b03909316963388141580612a96575b612a87576040519160c083018381106001600160401b03821117612a735760405288835260208301938452604083019486865260608401878152608085019088825260a08601928352833b15610efc57604051633116e47560e01b815295516001600160a01b03908116600488015296516024870152965160448601529551909416606484015293516084830152915160a4820152918391839160c49183915af180156108f257906001600160801b03939291612a63575b50505460701c16600f0b91600052602052604060002055565b81612a6d9161255d565b38612a4a565b634e487b7160e01b87526041600452602487fd5b6388935db960e01b8552600485fd5b50838110612992565b9050610240813d8211612c0f575b81612abb610240938361255d565b810103126107535760405190612ad082612541565b805182526020810151602083015260408101518015158103610737576040830152612afd60608201612809565b6060830152612b0e60808201612809565b6080830152612b1f60a08201612809565b60a0830152612b3060c08201612809565b60c0830152612b4160e08201612809565b60e0830152612b536101008201612809565b610100830152612b666101208201612809565b610120830152612b796101408201612809565b610140830152612b8c6101608201612809565b610160830152612b9f6101808201612809565b610180830152612bb26101a08201612809565b6101a08301526101c08101516001600160601b0381168103610737576101c08301526101e08101516001600160a01b03811681036107375790610220916101e084015261020081015161020084015201516102208201523861297a565b3d9150612aad565b637863668360e01b8252600482fd5b5464ffffffffff8160201c164210908115612c54575b50612c4357565b634065aaf160e11b60005260046000fd5b64ffffffffff915060481c16421138612c3c565b600094939192906001600160a01b031680612c84575b50505050565b9091929450604051948060005260408414612d30575b60418414612cf3575b946020939495600060605281604052630b135d3f60e11b8252600482015260648560248301968795604087528160448601528385013701915afa9051630b135d3f60e11b14169038808080612c7e565b604083013560001a60205260408381376020600160806000825afa5182183d1517612ca35750505050600191600060605260405238808080612c7e565b60208381013560ff81901c601b01825284356040526001600160ff1b0316606052600160806000825afa5182183d1517612c9a5750505050600191600060605260405238808080612c7e565b6001600160e01b031981166242006960e01b03612eaa576000526005602052604060002060405190612dad826124f5565b548060070b825264ffffffffff60208301918060401c60030b835260601c1680604084015260405163e18910a360e01b815260208160048160018060a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa908115612e9e57600091612e6c575b50420390428211612e565710612e4557612e42915160070b905160030b906131b3565b90565b630cd5fa0760e11b60005260046000fd5b634e487b7160e01b600052601160045260246000fd5b90506020813d602011612e96575b81612e876020938361255d565b810103126102b3575138612e1f565b3d9150612e7a565b6040513d6000823e3d90fd5b6040516331d98b3f60e01b815260048101919091526080816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015612e9e57600090612f17575b612e4291506040815160070b91015160030b906131b3565b5060803d608011612f4c575b612f2d818361255d565b8101906080818303126102b357612e4291612f479161281d565b612eff565b503d612f23565b6000808212612f60575090565b600160ff1b8214612f6f570390565b634e487b7160e01b81526011600452602490fd5b69021e19e0c9bab2400000909291920590819060028110156130265761301d576001915b620f4240811215612fc3575050620f4240600254830205020190565b629896801315612fdd57506207a120600254830205020190565b6000906207a12060025485020590629896806003548602055b6298968082121561300957505001020190565b9092611f0782612710920194020590612ff6565b60001991612fa7565b634e487b7160e01b600052602160045260246000fd5b9060018060a01b03166000526003810160205260406000209060405161306181612526565b6001835493848352015464ffffffffff811660208301528060281c600c0b604083015260901c600c0b6060820152821561312657612710926001613118930190806000528160205260406000205460070b151560001461311c576000526020526131016040600020604051906130d6826124f5565b54908160070b90818152604064ffffffffff84821c60030b9485602085015260601c169101526131b3565b6060906040830151600c0b9003910151600c0b0290565b0590565b6131019150612d7c565b505050600090565b60018060a01b031680638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3638b78c6d81955565b638b78c6d8600c526000526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3565b90601119600382900b12156131e2579063ffffffff612e429260120160030b60000316600a0a9060070b61277f565b63ffffffff9060120116600a0a9060070b029056fec1c8f5dd8ba0a07eb2a8a0b712b36ad1cc969c7f934c8decf86f98390b197ca412cce1add089ae91857f01bb906472895a65b5f522b9d100325a7f551e530f5ca26469706673582212204bd0c5a03a900e82ca61e3b0968be7ffbaee172c0d8d5625b735d0f6e047ac9064736f6c634300081c00330000000000000000000000002880ab155794e7179c9ee2e38200202908c17b430000000000000000000000003b44bda7a37ba06cb4272f0775e4ceea453cac5600000000000000000000000048b62137edfa95a428d35c09e44256a739f6b5570000000000000000000000007a114d38a11b8b4dc2f74555b5b2bb1f5bd742c9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000001

Deployed Bytecode

0x6080604052600436101561001b575b361561001957600080fd5b005b6000803560e01c8063032e9c761461240a5780630989e8df146121f55780630aa4001814612158578063183a4f6e1461213f57806318d913bd1461212157806319a4edb1146120615780631c10893f14611fff5780631cd64df414611fc557806323a1625614611fa95780632569296214611f5e57806326097b5a14611f3d5780632de9480714611f0a57806330a4d88114611eb35780633ccfd60b14611e725780633d46f265146114885780634a4ee7b11461145f5780634d22beb3146114385780634e609e32146113d2578063514e62fc1461139957806354343c551461118257806354d1f13d1461113c5780636717e41c1461110d5780636e5f7d06146110ef578063715018a6146110a45780637503e1b7146110365780637ed3a26414610fc85780638519870514610f7e5780638da5cb5b14610f515780638efaaea914610f08578063b26c24bc14610956578063b2bedf2314610938578063b4e517f6146107fe578063b965cc6b146107c4578063d4f9365814610484578063dcfb21ed14610405578063e2a399e5146103ec578063f04e283e1461039e578063f2fde38b1461035f578063f4277a7e146102cc578063fc8e75041461021f5763fee81cf4146101ea575061000e565b3461021c57602036600319011261021c5761020361248a565b9063389a75e1600c5252602080600c2054604051908152f35b80fd5b503461021c578060031936011261021c57604051631b8acb1f60e21b8152906020826004817f0000000000000000000000003b44bda7a37ba06cb4272f0775e4ceea453cac566001600160a01b03165afa9081156102c05790610288575b602090604051908152f35b506020813d6020116102b8575b816102a26020938361255d565b810103126102b3576020905161027d565b600080fd5b3d9150610295565b604051903d90823e3d90fd5b503461021c57604036600319011261021c576040816060928280516102f0816124f5565b82815282602082015201526004358152600460205260018282200160243582526020522064ffffffffff60405191610327836124f5565b548060070b92838152826040602083019284821c60030b84520192861c1682526040519384525160030b602084015251166040820152f35b50602036600319011261021c5761037461248a565b61037c6128dc565b8060601b156103915761038e9061312e565b80f35b637448fbae82526004601cfd5b50602036600319011261021c576103b361248a565b6103bb6128dc565b63389a75e1600c528082526020600c20805442116103df57908261038e925561312e565b636f5e881883526004601cfd5b50602036600319011261021c5761038e600435336128eb565b503461021c57602036600319011261021c5761041f61248a565b6104276128bb565b6001600160a01b031680156104755781546001600160a01b031916811782556040519081527f433d5aa4c8f989b56375c20361c91cb7dca10cebc7e123572fa796421e85251e90602090a180f35b63d92e233d60e01b8252600482fd5b503461021c57610493366124a0565b92909361049e612889565b85526004602052604085209364ffffffffff855460481c16924284116107b55760405163d47eed4560e01b81526020600482018190527f0000000000000000000000002880ab155794e7179c9ee2e38200202908c17b436001600160a01b031695919390848061051260248201878a61257e565b0381895afa9384156107aa578994610776575b5060058201906001600160401b03821161076257916001600160401b036105749694926105868c9997956040519b8c9a8b998a98634716e9c560e01b8a52608060048b015260848a019161257e565b878103600319016024890152916127e5565b92604485015216606483015203925af190811561075757839161065b575b5090600101825b8251811015610657578060206105c360019386612875565b510151805160070b9064ffffffffff6060604083015160030b92015116604051926105ed846124f5565b835260208301918252604083019081526106078488612875565b5151885285602052604088209251916001600160401b038454915160401b9264ffffffffff60601b905160601b169316906001600160881b031916179063ffffffff60401b1617179055016105ab565b8380f35b90503d8084833e61066c818361255d565b81019060208183031261074f578051906001600160401b038211610753570181601f8201121561074f578051906001600160401b03821161073b57604051926106bb60208460051b018561255d565b828452602061012081860194028301019181831161073757602001925b8284106106e95750505050386105a4565b6101208483031261073757602061012091604051610706816124f5565b865181526107168584890161281d565b838201526107278560a0890161281d565b60408201528152019301926106d8565b8680fd5b634e487b7160e01b85526041600452602485fd5b8380fd5b8480fd5b6040513d85823e3d90fd5b634e487b7160e01b8a52601160045260248afd5b9093506020813d6020116107a2575b816107926020938361255d565b810103126102b357519238610525565b3d9150610785565b6040513d8b823e3d90fd5b634a65fe1160e01b8752600487fd5b503461021c57604036600319011261021c576107f660209160406107e6612474565b916004358152600485522061303c565b604051908152f35b503461021c57604036600319011261021c57602435906001600160401b03821161021c573660238301121561021c5781600401356001600160401b038111610934573660248260061b8501011161093457610857612889565b7f0000000000000000000000003b44bda7a37ba06cb4272f0775e4ceea453cac566001600160a01b031692833b156109305760405191639eed5e2160e01b835280606484016004356004860152856024860152606060448601525260246084840192019084905b8082106108fd57505050818394818581819503925af180156108f2576108e15750f35b816108eb9161255d565b61021c5780f35b6040513d84823e3d90fd5b909192833560018060a01b03811680910361073757604082819260019452602087013560208201520194019201906108be565b8280fd5b5080fd5b503461021c578060031936011261021c576020600354604051908152f35b503461021c5761012036600319011261021c576004356001600160401b03811161093457610988903690600401612444565b906024359161ffff8316830361074f5760443564ffffffffff81168103610753576064359364ffffffffff85168503610f04576001600160801b036084351660843503610f045760a4359061ffff821682036107375760c43569ffffffffffffffffffff81168103610f005760e435926001600160401b0384168403610efc57610a10612889565b64ffffffffff808616818a160311610ee85760405197610a2f89612541565b69ffffffffffffffffffff8316895269ffffffffffffffffffff831660208a0152600160408a01526001600160401b0360608a01526001600160401b0360808a01526001600160401b03851660a08a015264ffffffffff861660c08a015264ffffffffff811660e08a0152670de0b6b3a76400006101008a0152670de0b6b3a76400006101208a0152670de0b6b3a76400006101408a015264ffffffffff80871681831603166101608a0152896101808a015262278d006101a08a0152896101c08a015260018060a01b037f00000000000000000000000048b62137edfa95a428d35c09e44256a739f6b557166101e08a0152610104356102008a0152896102208a0152610220604051996328889c6d60e21b8b52805160048c0152602081015160248c01526040810151151560448c01526001600160401b0360608201511660648c01526001600160401b0360808201511660848c01526001600160401b0360a08201511660a48c01526001600160401b0360c08201511660c48c01526001600160401b0360e08201511660e48c01526001600160401b03610100820151166101048c01526001600160401b03610120820151166101248c01526001600160401b03610140820151166101448c01526001600160401b03610160820151166101648c01526001600160401b03610180820151166101848c01526001600160401b036101a0820151166101a48c01526001600160601b036101c0820151166101c48c015260018060a01b036101e0820151166101e48c01526102008101516102048c015201516102248a0152602089610244818d60018060a01b037f0000000000000000000000003b44bda7a37ba06cb4272f0775e4ceea453cac56165af1988915610edd578a99610ea9575b507f0000000000000000000000003b44bda7a37ba06cb4272f0775e4ceea453cac566001600160a01b03163b15610e9a57604051637aac643f60e01b8152600481018a9052602481018b905264ffffffffff871660448201528a81606481837f0000000000000000000000003b44bda7a37ba06cb4272f0775e4ceea453cac566001600160a01b03165af18015610e9e57610e85575b508989809b5260046020526040902080548360101b63ffff0000169063ffff000019906001600160801b0360701b199061ffff8916906dffffffffffffffffffff0000ffff191617168960201b68ffffffffff000000001617168360481b6dffffffffff00000000000000000016176001600160801b0360701b60843560701b16171790556040519788976101208952610120890190610df1926127e5565b9564ffffffffff16602088015264ffffffffff1660408701526084356001600160801b0316606087015261ffff16608086015269ffffffffffffffffffff1660a085015261ffff1660c08401526001600160401b031660e083015261010435610100830152037f07f0d15dca459300ceadf62f30ae8e6b90af800ea554cc7530cc837b96b5d50991a2604051908152602090f35b610e908b809261255d565b610e9a5738610d52565b8980fd5b6040513d8d823e3d90fd5b9098506020813d602011610ed5575b81610ec56020938361255d565b810103126102b357519738610cbc565b3d9150610eb8565b6040513d8c823e3d90fd5b634e487b7160e01b89526011600452602489fd5b8880fd5b8780fd5b8580fd5b503461021c57602036600319011261021c57604060609160043581526005602052205464ffffffffff604051918060070b83528060401c60030b6020840152831c166040820152f35b503461021c578060031936011261021c57638b78c6d819546040516001600160a01b039091168152602090f35b503461021c57604036600319011261021c5760026040610f9c612474565b926004358152600460205220019060018060a01b03166000526020526020604060002054604051908152f35b503461021c57602036600319011261021c57600435610fe56128bb565b683635c9adc5dea000008111611027576020817fa6635fc6998b0f79d9889a9d1cba35ab931d2e68ebe46f897c1fb915a5b874e492600155604051908152a180f35b63263d748960e11b8252600482fd5b503461021c57602036600319011261021c57604060a0916004358152600460205220546001600160801b036040519161ffff8116835261ffff8160101c16602084015264ffffffffff8160201c16604084015264ffffffffff8160481c16606084015260701c166080820152f35b508060031936011261021c576110b86128dc565b80638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380638b78c6d8195580f35b503461021c578060031936011261021c576020600154604051908152f35b503461021c57602036600319011261021c5760ff60406020926004358152600684522054166040519015158152f35b508060031936011261021c5763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b503461021c576111b5611194366124a0565b848796929394959652600460205260408720926111b084612c26565b612617565b8493859360028301925b848610611225578787806111d1575080f35b8180808084335af16111e1612740565b5015611216576040519081527f0b8af83edb58a3c0794e9aadbac8779b13e493370e536255cf3b1a7da9239d3e60203392a280f35b6312171d8360e31b8252600482fd5b90919293949561124761124161123c89898761271a565b6127d1565b8361303c565b604061125761123c8a8a8861271a565b6001600160a01b0316600090815260208890522054818101908a831280159183129182169115161761076257891315611326575060019088604061129f61123c8b8b8961271a565b600090858060a01b03168152886020522055888260406112c361123c8c8c8a61271a565b600090838060a01b031681526003870160205220828155015581540196818060a01b036112f461123c838a8861271a565b16857f03b910a1639200ab2b0061788a7e4d39f45a305c900ac7f92a77b9a8447df9dc8b80a35b0194939291906111bf565b9660019197857fdc57291b7b129d2079685e49dc1d00cea767d4f624f9523d658fd5ce90a6469660408a8161136e61123c8861136761123c828f889061271a565b948d61271a565b600090898060a01b031681528c60205220549482519586526020860152868060a01b031693a361131b565b503461021c57604036600319011261021c576113b361248a565b90638b78c6d8600c5252602060243581600c2054161515604051908152f35b503461021c57602036600319011261021c576004356113ef6128bb565b600a8111611429576020817f3fff8b1775def0fb5bb8d5be4d00c6de3f320bd44db6653469073a7ded6ddb6992600355604051908152a180f35b63428637bb60e11b8252600482fd5b503461021c578060031936011261021c57546040516001600160a01b039091168152602090f35b50604036600319011261021c5761038e61147761248a565b61147f6128dc565b6024359061316c565b503461021c5761010036600319011261021c576044356001600160401b038111610934576114ba903690600401612444565b608435906001600160a01b038216820361074f5760e435906001600160401b0382116107535736602383011215610753576001600160401b03826004013511610753573660248360040135840101116107535760643515611e635760a4354210611e5457601e60a435014211611e4557600435855260046020526040852061154181612c26565b60018060a01b038416600052600381016020526040600020916040519561156787612526565b6001845494858952015464ffffffffff811660208901528060281c600c0b60408901528060901c600c0b6060890152889480611dce575b505060c4358852600660205260ff604089205416611dc05760c4358852600660205260408820805460ff19166001179055606435881215611db85787945b6040516001600160601b03198860601b166020820152600435603482015260243560548201526002871015611da4578660f81b607482015260a435607582015260c43560958201526095815261163360b58261255d565b805160209182012090527b19457468657265756d205369676e6564204d6573736167653a0a33328952603c600420336001600160a01b03891603611d6d578954611691926004810135926024909101916001600160a01b0316612c68565b15611d5e57906116a091612617565b6116ab602435612d7c565b916116c98387906060906040830151600c0b9003910151600c0b0290565b90600283019460018060a01b03871660005285602052604060002054916116f660608a0151600c0b612f53565b916127108061ffff885460101c168782880201020581898602059084600014611d5857015b02611727606435612f53565b92888402918d8512600160ff1b8b1416611d44578483058a1485151715611d4457808313611d1e575015611bb557508183036118a157505050611817939495965060018060a01b03871660005285602052612710604060002092050190556040519061179282612526565b868252602082019164ffffffffff4216835264ffffffffff80600160408401938b8552600360608201968d8852838060a01b038d1660005201602052604060002090518155019451161664ffffffffff198454161783555182549060281b600160281b600160901b031690600160281b600160901b03191617825551600c0b9061279f565b6040805160643581526020810192909252602435908201526001600160a01b0383169060c435906004359060008051602061321883398151915290606090a460018060a01b038216600052602052604060002054906040519083825283602083015283604083015260018060a01b0316906000805160206131f8833981519152606060043592a480f35b939796959493828212156119cb57506118d560039493926127109260608c0151600c0b606435600c0b01600c0b9a0261277f565b050160018060a01b0386166000528460205260406000205560018060a01b03851660005281810160205261191086600160406000200161279f565b6001600160a01b0385166000818152919092016020908152604091829020600101805464ffffffffff421664ffffffffff199091161790558151606435815290810193909352602435908301529060c435906004359060008051602061321883398151915290606090a460018060a01b03821660005260205260408060002054930151600c0b6040519283526020830152602435604083015260018060a01b0316906000805160206131f8833981519152606060043592a480f35b949396989150506060919682820151600c0b606435600c0b01600c0b9760018060a01b038a1660005286602052612710604060002092050190550151600c0b870380600c0b908103611ba15760408051600c9290920b82526020820183905260243590820152611b0a92611a729290916001600160a01b0389169060c435906004359060008051602061321883398151915290606090a4611a6d818802612f53565b612f83565b9260405190611a8082612526565b6024358252602082019164ffffffffff4216835264ffffffffff806001604084019389600c0b8552600360608201968c88528d848060a01b031660005201602052604060002090518155019451161664ffffffffff198454161783555182549060281b600160281b600160901b031690600160281b600160901b03191617825551600c0b9061279f565b60408051600c85900b815260208101849052602435918101919091526001600160a01b0385169060c435906004359060008051602061321883398151915290606090a46001600160a01b039390931660008181526020948552604090819020548151600c9590950b8552948401929092526024359183019190915290600435906000805160206131f883398151915290606090a480f35b634e487b7160e01b88526011600452602488fd5b611c8b9550611bf9945096611bd092939698979a999a612f83565b938181604060608b0151600c0b606435600c0b01600c0b9a0151600c0b0291019185020161277f565b93858764ffffffffff806001604051611c1181612526565b602435815260036020820197844216895260408301968d600c0b885260608401988952848060a01b031660005201602052604060002090518155019451161664ffffffffff198454161783555182549060281b600160281b600160901b031690600160281b600160901b03191617825551600c0b9061279f565b6040805160643581526020810192909252602435908201526001600160a01b0385169060c435906004359060008051602061321883398151915290606090a46001600160a01b039390931660008181526020948552604090819020548151600c9590950b8552948401929092526024359183019190915290600435906000805160206131f883398151915290606090a480f35b8d83828260449412611d3d575b63e3f3d0e360e01b8352600452602452fd5b5081611d2b565b634e487b7160e01b8e52601160045260248efd5b0361171b565b638baa579f60e01b8852600488fd5b8954336001600160a01b0390911603611d955790611691916024826004013592019089612c68565b6348f5c3ed60e01b8a5260048afd5b634e487b7160e01b8a52602160045260248afd5b6001946115dc565b623f613760e71b8852600488fd5b60243514611de557630631dbcd60e11b8952600489fd5b8860643513898260901c600c0b1303611e01575b50388061159e565b90935064ffffffffff61ffff84541691160164ffffffffff8111611ba15764ffffffffff42911611611e365760019238611df9565b633e7c0cc760e11b8752600487fd5b630819bdcd60e01b8552600485fd5b631abad6d560e11b8552600485fd5b63162908e360e11b8552600485fd5b503461021c578060031936011261021c57611e8b6128dc565b8080808047335af1611e9b612740565b5015611ea45780f35b6312171d8360e31b8152600490fd5b503461021c57602036600319011261021c57600435611ed06128bb565b60fa8111611429576020817fd7bf6fb5afa6dde675c1b0e83381bb3d5dc5a0f4711c590e63a0a4ec6494395e92600255604051908152a180f35b503461021c57602036600319011261021c57611f2461248a565b90638b78c6d8600c5252602080600c2054604051908152f35b50604036600319011261021c5761038e611f5561248a565b602435906128eb565b508060031936011261021c5763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b503461021c578060031936011261021c576020604051601e8152f35b503461021c57604036600319011261021c57602090611fe261248a565b60243591638b78c6d8600c52528082600c20541614604051908152f35b50604036600319011261021c5761201461248a565b61201c6128dc565b638b78c6d8600c5281526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe268380a380f35b503461021c57604036600319011261021c576003604061207f612474565b92806060835161208e81612526565b828152826020820152828582015201526004358152600460205220019060018060a01b0316600052602052608060406000206040516120cc81612526565b600182549283835201549064ffffffffff602082018184168152606060408401938560281c600c0b8552019360901c600c0b84526040519485525116602084015251600c0b604083015251600c0b6060820152f35b503461021c578060031936011261021c576020600254604051908152f35b50602036600319011261021c5761038e6004353361316c565b503461021c57602036600319011261021c57612172612889565b807f0000000000000000000000003b44bda7a37ba06cb4272f0775e4ceea453cac566001600160a01b0316803b156121f257818091604460405180958193633d1a69db60e21b835260043560048401528160248401525af180156121e5576121d75780f35b6121e09161255d565b388180f35b50604051903d90823e3d90fd5b50fd5b503461021c57604036600319011261021c576004356001600160401b03811161093457612226903690600401612444565b602435916001600160401b03831161074f573660238401121561074f578260040135926001600160401b03841161075357366024606086028301011161075357638b78c6d8600c52338552600160581b6020600c205416156123fd578383036123ee57845b838110612296578580f35b848110156123da576060810282016060602319823603011261073757604051906122bf826124f5565b60248101358060070b8103610efc5782526044810135908160030b8203610efc57602083019182526064013564ffffffffff81168103610efc576040830190815261230b84888861271a565b3560016242006960e01b03196001600160e01b03198216016123cb574264ffffffffff835116116123bc579060019493929164ffffffffff825116818c52600560205264ffffffffff60408d205460601c1610156123b3578a52600560205260408a209251916001600160401b038454915160401b9264ffffffffff60601b905160601b169316906001600160881b031916179063ffffffff60401b16171790555b0161228b565b505050506123ad565b63b7d0949760e01b8a5260048afd5b631bd2d0af60e01b8a5260048afd5b634e487b7160e01b86526032600452602486fd5b63512509d360e11b8552600485fd5b6382b4290085526004601cfd5b503461021c57602036600319011261021c576004356001600160401b0381116109345761243e61038e913690600401612444565b90612617565b9181601f840112156102b3578235916001600160401b0383116102b3576020808501948460051b0101116102b357565b602435906001600160a01b03821682036102b357565b600435906001600160a01b03821682036102b357565b9060606003198301126102b357600435916024356001600160401b0381116102b357816124cf91600401612444565b92909291604435906001600160401b0382116102b3576124f191600401612444565b9091565b606081019081106001600160401b0382111761251057604052565b634e487b7160e01b600052604160045260246000fd5b608081019081106001600160401b0382111761251057604052565b61024081019081106001600160401b0382111761251057604052565b90601f801991011681019081106001600160401b0382111761251057604052565b90602083828152019060208160051b85010193836000915b8383106125a65750505050505090565b909192939495601f198282030186528635601e19843603018112156102b357830190602082359201916001600160401b0381116102b35780360383136102b3576020828280600196849695859652848401376000828201840152601f01601f19160101980196019493019190612596565b6000918061262457505050565b60405163d47eed4560e01b81526020600482018190527f0000000000000000000000002880ab155794e7179c9ee2e38200202908c17b436001600160a01b0316929190818061267760248201868961257e565b0381865afa90811561270f5785916126dd575b50823b1561075357916126be93918593604051809681958294631df3cbc560e31b845260206004850152602484019161257e565b03925af180156108f2576126d0575050565b816126da9161255d565b50565b90506020813d602011612707575b816126f86020938361255d565b8101031261075357513861268a565b3d91506126eb565b6040513d87823e3d90fd5b919081101561272a5760051b0190565b634e487b7160e01b600052603260045260246000fd5b3d1561277a573d906001600160401b038211612510576040519161276e601f8201601f19166020018461255d565b82523d6000602084013e565b606090565b8115612789570590565b634e487b7160e01b600052601260045260246000fd5b9081549060901b6cffffffffffffffffffffffffff60901b16906cffffffffffffffffffffffffff60901b1916179055565b356001600160a01b03811681036102b35790565b81835290916001600160fb1b0383116102b35760209260051b809284830137010190565b51906001600160401b03821682036102b357565b91908260809103126102b35760405161283581612526565b809280518060070b81036102b357825261285160208201612809565b602083015260408101518060030b81036102b3576040830152606090810151910152565b805182101561272a5760209160051b010190565b638b78c6d8600c5233600052682000000000000000006020600c205416156128ad57565b6382b429006000526004601cfd5b638b78c6d8600c5233600052650400000000006020600c205416156128ad57565b638b78c6d8195433036128ad57565b600082815260046020526040812090600282019260018060a01b0381168252836020526040822054612c175761292083612c26565b60015434039460018060a01b037f0000000000000000000000003b44bda7a37ba06cb4272f0775e4ceea453cac5616604051630696f5ff60e21b815282600482015261024081602481855afa90811561270f578591612a9f575b50516001600160a01b03909316963388141580612a96575b612a87576040519160c083018381106001600160401b03821117612a735760405288835260208301938452604083019486865260608401878152608085019088825260a08601928352833b15610efc57604051633116e47560e01b815295516001600160a01b03908116600488015296516024870152965160448601529551909416606484015293516084830152915160a4820152918391839160c49183915af180156108f257906001600160801b03939291612a63575b50505460701c16600f0b91600052602052604060002055565b81612a6d9161255d565b38612a4a565b634e487b7160e01b87526041600452602487fd5b6388935db960e01b8552600485fd5b50838110612992565b9050610240813d8211612c0f575b81612abb610240938361255d565b810103126107535760405190612ad082612541565b805182526020810151602083015260408101518015158103610737576040830152612afd60608201612809565b6060830152612b0e60808201612809565b6080830152612b1f60a08201612809565b60a0830152612b3060c08201612809565b60c0830152612b4160e08201612809565b60e0830152612b536101008201612809565b610100830152612b666101208201612809565b610120830152612b796101408201612809565b610140830152612b8c6101608201612809565b610160830152612b9f6101808201612809565b610180830152612bb26101a08201612809565b6101a08301526101c08101516001600160601b0381168103610737576101c08301526101e08101516001600160a01b03811681036107375790610220916101e084015261020081015161020084015201516102208201523861297a565b3d9150612aad565b637863668360e01b8252600482fd5b5464ffffffffff8160201c164210908115612c54575b50612c4357565b634065aaf160e11b60005260046000fd5b64ffffffffff915060481c16421138612c3c565b600094939192906001600160a01b031680612c84575b50505050565b9091929450604051948060005260408414612d30575b60418414612cf3575b946020939495600060605281604052630b135d3f60e11b8252600482015260648560248301968795604087528160448601528385013701915afa9051630b135d3f60e11b14169038808080612c7e565b604083013560001a60205260408381376020600160806000825afa5182183d1517612ca35750505050600191600060605260405238808080612c7e565b60208381013560ff81901c601b01825284356040526001600160ff1b0316606052600160806000825afa5182183d1517612c9a5750505050600191600060605260405238808080612c7e565b6001600160e01b031981166242006960e01b03612eaa576000526005602052604060002060405190612dad826124f5565b548060070b825264ffffffffff60208301918060401c60030b835260601c1680604084015260405163e18910a360e01b815260208160048160018060a01b037f0000000000000000000000002880ab155794e7179c9ee2e38200202908c17b43165afa908115612e9e57600091612e6c575b50420390428211612e565710612e4557612e42915160070b905160030b906131b3565b90565b630cd5fa0760e11b60005260046000fd5b634e487b7160e01b600052601160045260246000fd5b90506020813d602011612e96575b81612e876020938361255d565b810103126102b3575138612e1f565b3d9150612e7a565b6040513d6000823e3d90fd5b6040516331d98b3f60e01b815260048101919091526080816024817f0000000000000000000000002880ab155794e7179c9ee2e38200202908c17b436001600160a01b03165afa8015612e9e57600090612f17575b612e4291506040815160070b91015160030b906131b3565b5060803d608011612f4c575b612f2d818361255d565b8101906080818303126102b357612e4291612f479161281d565b612eff565b503d612f23565b6000808212612f60575090565b600160ff1b8214612f6f570390565b634e487b7160e01b81526011600452602490fd5b69021e19e0c9bab2400000909291920590819060028110156130265761301d576001915b620f4240811215612fc3575050620f4240600254830205020190565b629896801315612fdd57506207a120600254830205020190565b6000906207a12060025485020590629896806003548602055b6298968082121561300957505001020190565b9092611f0782612710920194020590612ff6565b60001991612fa7565b634e487b7160e01b600052602160045260246000fd5b9060018060a01b03166000526003810160205260406000209060405161306181612526565b6001835493848352015464ffffffffff811660208301528060281c600c0b604083015260901c600c0b6060820152821561312657612710926001613118930190806000528160205260406000205460070b151560001461311c576000526020526131016040600020604051906130d6826124f5565b54908160070b90818152604064ffffffffff84821c60030b9485602085015260601c169101526131b3565b6060906040830151600c0b9003910151600c0b0290565b0590565b6131019150612d7c565b505050600090565b60018060a01b031680638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3638b78c6d81955565b638b78c6d8600c526000526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3565b90601119600382900b12156131e2579063ffffffff612e429260120160030b60000316600a0a9060070b61277f565b63ffffffff9060120116600a0a9060070b029056fec1c8f5dd8ba0a07eb2a8a0b712b36ad1cc969c7f934c8decf86f98390b197ca412cce1add089ae91857f01bb906472895a65b5f522b9d100325a7f551e530f5ca26469706673582212204bd0c5a03a900e82ca61e3b0968be7ffbaee172c0d8d5625b735d0f6e047ac9064736f6c634300081c0033

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

0000000000000000000000002880ab155794e7179c9ee2e38200202908c17b430000000000000000000000003b44bda7a37ba06cb4272f0775e4ceea453cac5600000000000000000000000048b62137edfa95a428d35c09e44256a739f6b5570000000000000000000000007a114d38a11b8b4dc2f74555b5b2bb1f5bd742c9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000001

-----Decoded View---------------
Arg [0] : pyth (address): 0x2880aB155794e7179c9eE2e38200202908C17B43
Arg [1] : reboot (address): 0x3B44BDa7a37ba06CB4272f0775E4CEEa453CAc56
Arg [2] : wape (address): 0x48b62137EdfA95a428D35C09E44256a739F6B557
Arg [3] : signer (address): 0x7A114d38a11B8B4Dc2f74555b5B2BB1f5BD742c9
Arg [4] : _liquidationBounty (uint256): 0
Arg [5] : _baseSlippage (uint256): 25
Arg [6] : _slippageIncrement (uint256): 1

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000002880ab155794e7179c9ee2e38200202908c17b43
Arg [1] : 0000000000000000000000003b44bda7a37ba06cb4272f0775e4ceea453cac56
Arg [2] : 00000000000000000000000048b62137edfa95a428d35c09e44256a739f6b557
Arg [3] : 0000000000000000000000007a114d38a11b8b4dc2f74555b5b2bb1f5bd742c9
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001


Deployed Bytecode Sourcemap

971:32794:6:-:0;;;;;;;;;-1:-1:-1;971:32794:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4811:9;971:32794;4811:9;;;971:32794;25547:25;;;971:32794;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;:::i;:::-;11885:237:3;;;;;971:32794:6;11885:237:3;;;;971:32794:6;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;25547:25:6;;971:32794;25547:25;971:32794;;;25547:7;-1:-1:-1;;;;;971:32794:6;25547:25;;;;;;;;;;971:32794;25547:25;971:32794;;;;;;;25547:25;;;;;;;;;;;;971:32794;25547:25;;;:::i;:::-;;;971:32794;;;;25547:25;971:32794;;25547:25;;971:32794;-1:-1:-1;971:32794:6;;25547:25;;;-1:-1:-1;25547:25:6;;;971:32794;;;;;;;;;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;4811:9;971:32794;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;23856:37;971:32794;;;;;;;;;;;;;;:::i;:::-;;;;;4811:9;;;;971:32794;;;;;;;;;;;4811:9;;971:32794;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;971:32794:6;;-1:-1:-1;;971:32794:6;;;;;;:::i;:::-;12478:70:3;;:::i;:::-;8479:183;;;;;;8681:8;;;:::i;:::-;971:32794:6;;8479:183:3;;;;971:32794:6;8479:183:3;;971:32794:6;-1:-1:-1;971:32794:6;;-1:-1:-1;;971:32794:6;;;;;;:::i;:::-;12478:70:3;;:::i;:::-;10506:526;;;;;;971:32794:6;10506:526:3;;;;;;;;;;11051:12;10506:526;;11051:12;:::i;10506:526::-;;;;971:32794:6;10506:526:3;;971:32794:6;-1:-1:-1;971:32794:6;;-1:-1:-1;;971:32794:6;;;;9464:12;971:32794;;9452:10;9464:12;:::i;971:32794::-;;;;;;;-1:-1:-1;;971:32794:6;;;;;;:::i;:::-;11745:5:4;;:::i;:::-;-1:-1:-1;;;;;971:32794:6;28084:20;;28080:46;;971:32794;;-1:-1:-1;;;;;;971:32794:6;;;;;;;;;;28180:33;;971:32794;;28180:33;971:32794;;28080:46;-1:-1:-1;;;28113:13:6;;971:32794;28113:13;;971:32794;;;;;;;;:::i;:::-;11745:5:4;;;;;:::i;:::-;971:32794:6;;;;;;;;;;;;;;;22352:15;;22331:36;;22327:67;;971:32794;;-1:-1:-1;;;22419:32:6;;971:32794;;22419:32;;971:32794;;;22419:5;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;:::i;:::-;22419:32;;;;;;;;;;;;;;971:32794;4811:9;;;;;-1:-1:-1;;;;;4811:9:6;;;;971:32794;-1:-1:-1;;;;;4811:9:6;971:32794;;;4811:9;971:32794;;;;;;;;;;;;;;;;22505:152;;4811:9;971:32794;22505:152;;4811:9;;;;;;:::i;:::-;;;;-1:-1:-1;;4811:9:6;971:32794;4811:9;;;971:32794;4811:9;:::i;:::-;;;;;;971:32794;4811:9;;;971:32794;22505:152;;;;;;;;;;;;;971:32794;-1:-1:-1;22673:13:6;22861:22;;22673:13;22711:3;971:32794;;22688:21;;;;;22763:13;971:32794;22763:13;22861:22;22763:13;;;:::i;:::-;;:19;;971:32794;;;;22961:10;971:32794;4811:9;971:32794;22961:10;;971:32794;;;22993:17;;4811:9;971:32794;;;;;;;:::i;:::-;4811:9;;971:32794;22920:93;;4811:9;;;971:32794;22920:93;;971:32794;;;22884:13;;;;:::i;:::-;;971:32794;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;4811:9;971:32794;;;;;-1:-1:-1;;;;;971:32794:6;;;;-1:-1:-1;;;971:32794:6;;;;;;22673:13;;22688:21;;971:32794;;22505:152;;;;;;;;;;;;:::i;:::-;;;4811:9;971:32794;4811:9;;;;;;;;;-1:-1:-1;;;;;4811:9:6;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4811:9:6;;;;971:32794;;4811:9;971:32794;;4811:9;;;;971:32794;;:::i;:::-;4811:9;;;971:32794;4811:9;;;;;;;;;;;;;;;971:32794;4811:9;;;;;;;;22505:152;;;;;;;4811:9;;;;;;;;971:32794;4811:9;971:32794;;;;;;:::i;:::-;4811:9;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;971:32794;4811:9;;;;;;;;;;;;971:32794;;;4811:9;-1:-1:-1;;;971:32794:6;;;;;;;;4811:9;971:32794;;;4811:9;971:32794;;;22505:152;971:32794;;;;;;;;;4811:9;-1:-1:-1;;;971:32794:6;;;;;;;;22419:32;;;;971:32794;22419:32;;971:32794;22419:32;;;;;;971:32794;22419:32;;;:::i;:::-;;;971:32794;;;;;22419:32;;;;;;;-1:-1:-1;22419:32:6;;;971:32794;;;;;;;;;22327:67;-1:-1:-1;;;22376:18:6;;971:32794;22376:18;;971:32794;;;;;;;-1:-1:-1;;971:32794:6;;;;26852:32;971:32794;;;;;:::i;:::-;;;;;;;;;;26852:32;:::i;:::-;971:32794;;;;;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;11745:5:4;;:::i;:::-;24827:7:6;-1:-1:-1;;;;;971:32794:6;;24827:47;;;;;971:32794;;;;;;24827:47;;971:32794;;;;;;;24827:47;;971:32794;;;;;;;;;;;;;;;;;;;;;;;;;;;24827:47;;;;;;;;;;;;;;;;;;;;;971:32794;;24827:47;;;;;:::i;:::-;971:32794;;24827:47;971:32794;24827:47;971:32794;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24827:47;971:32794;;;;;;;;;;;;;;;;;;;;;5599:44;971:32794;;;;;;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;11745:5:4;;:::i;:::-;971:32794:6;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;7724:800;;971:32794;;;7724:800;;971:32794;-1:-1:-1;;;;;971:32794:6;7724:800;;971:32794;-1:-1:-1;;;;;971:32794:6;7724:800;;971:32794;-1:-1:-1;;;;;971:32794:6;;;7724:800;;971:32794;;;;;7724:800;;971:32794;;;;;7724:800;;971:32794;8107:7;971:32794;7724:800;;971:32794;8107:7;971:32794;7724:800;;971:32794;8107:7;7724:800;;;971:32794;;;;;;;;;;7724:800;;;971:32794;7724:800;;;;971:32794;8334:7;7724:800;;;971:32794;7724:800;;;;971:32794;;;;;;8401:22;971:32794;7724:800;;;971:32794;;;7724:800;;;971:32794;7724:800;;;;971:32794;7724:800;971:32794;;;;;;7694:840;;971:32794;;;7694:840;;971:32794;;7724:800;;971:32794;;;;;;7724:800;;971:32794;;;;;;;-1:-1:-1;;;;;971:32794:6;7724:800;;971:32794;;;;;;-1:-1:-1;;;;;971:32794:6;7724:800;;971:32794;;;;;;-1:-1:-1;;;;;971:32794:6;7724:800;;971:32794;;;;;;-1:-1:-1;;;;;971:32794:6;7724:800;;971:32794;;;;;;-1:-1:-1;;;;;971:32794:6;7724:800;;971:32794;;;;;;-1:-1:-1;;;;;971:32794:6;7724:800;;971:32794;;;;;;-1:-1:-1;;;;;971:32794:6;7724:800;;971:32794;;;;;;-1:-1:-1;;;;;7724:800:6;;;971:32794;;;;;;-1:-1:-1;;;;;7724:800:6;;;971:32794;;;;;;-1:-1:-1;;;;;7724:800:6;;;971:32794;;;;;;-1:-1:-1;;;;;7724:800:6;;;971:32794;;;;;;-1:-1:-1;;;;;7724:800:6;;;971:32794;;;;;;;;;;;7724:800;;;971:32794;;;;;;7724:800;;;971:32794;;;;;7724:800;971:32794;;;;;;;7694:840;971:32794;;;;;;;7694:7;971:32794;7694:840;;;;;;;;;;;971:32794;-1:-1:-1;7694:7:6;-1:-1:-1;;;;;971:32794:6;8545:54;;;;971:32794;;-1:-1:-1;;;8545:54:6;;971:32794;8545:54;;971:32794;;;;;;;;;;;;;;;;;;;;;7694:7;-1:-1:-1;;;;;971:32794:6;8545:54;;;;;;;;971:32794;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;8926:275;;;;971:32794;;;;;;;;8545:54;;;;;;:::i;:::-;971:32794;;8545:54;;;971:32794;;;;8545:54;971:32794;;;;;;;;;7694:840;;;;971:32794;7694:840;;971:32794;7694:840;;;;;;971:32794;7694:840;;;:::i;:::-;;;971:32794;;;;;7694:840;;;;;;;-1:-1:-1;7694:840:6;;;971:32794;;;;;;;;;;-1:-1:-1;;;971:32794:6;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;;;;;;5735:66;971:32794;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;11523:61:3;971:32794:6;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;-1:-1:-1;;971:32794:6;;;;26223:37;971:32794;;;:::i;:::-;;;;;;;;;;26223:37;:43;971:32794;;;;;;-1:-1:-1;971:32794:6;;;;;-1:-1:-1;971:32794:6;;;;;;;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;11745:5:4;;:::i;:::-;29079:11:6;29070:20;;29066:59;;971:32794;4858:6;29178:32;4858:6;971:32794;4858:6;971:32794;;;;;29178:32;971:32794;;29066:59;-1:-1:-1;;;29099:26:6;;971:32794;29099:26;;971:32794;;;;;;;-1:-1:-1;;971:32794:6;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12478:70:3;;:::i;:::-;6813:405;4606:437:4;6813:405:3;;;;;;;4606:437:4;6813:405:3;;971:32794:6;;;;;;;;;;;;;;;;5516:32;971:32794;;;;;;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;;;;;;;5807:55;971:32794;;;;;;;;;;;;;;;;;;;;;;;9831:339:3;;;;;;;;;;;;;;;;971:32794:6;;;;;;;19627:12;971:32794;;;:::i;:::-;;;;;;;;;;;;;;;;19585:10;;;;:::i;:::-;19627:12;:::i;:::-;19651:31;19698:13;;19838:22;;;;19693:695;19713:16;;;;;;20402:27;;;20398:256;;971:32794;;;20398:256;20463:10;;;;;;:51;;;;:::i;:::-;;20532:8;20528:37;;971:32794;;;;;20585:58;971:32794;20463:10;20585:58;;971:32794;;20528:37;-1:-1:-1;;;20549:16:6;;971:32794;25361:16;20549;19731:3;19797:8;;;;;;19770:36;19797:8;;;;;;:::i;:::-;;:::i;:::-;19770:36;;:::i;:::-;971:32794;19861:8;;;;;;:::i;:::-;-1:-1:-1;;;;;971:32794:6;-1:-1:-1;971:32794:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;971:32794:6;;;19951:8;971:32794;19951:8;;971:32794;19951:8;;;;;;:::i;:::-;-1:-1:-1;971:32794:6;;;;;;;;;;;;;4858:6;20012:8;;971:32794;20012:8;;;;;;:::i;:::-;-1:-1:-1;971:32794:6;;;;;;;;;19989:22;;;971:32794;;;;;;;;;;;;;;;;;20182:8;;;;;;:::i;:::-;971:32794;20157:34;;;;;19821:557;971:32794;19698:13;;;;;;;19821:557;20308:8;971:32794;20308:8;;;20275:88;971:32794;20308:8;;20341;;20308;;;;;;;;:::i;:::-;20341;;;:::i;:::-;-1:-1:-1;971:32794:6;;;;;;;;;;;;;;;;;;;;;4858:6;;971:32794;;;;;;;20275:88;;19821:557;;971:32794;;;;;;;-1:-1:-1;;971:32794:6;;;;;;:::i;:::-;10695:219:4;;;;;971:32794:6;;;10695:219:4;;;;11083:21;:26;;971:32794:6;;;;;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;11745:5:4;;:::i;:::-;5325:2:6;28746:47;;28742:77;;971:32794;4858:6;28893:36;4858:6;28830:47;4858:6;971:32794;;;;;28893:36;971:32794;;28742:77;-1:-1:-1;;;28802:17:6;;971:32794;28437:17;28802;971:32794;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;-1:-1:-1;971:32794:6;;-1:-1:-1;;971:32794:6;;;;4408:5:4;971:32794:6;;:::i;:::-;12478:70:3;;:::i;:::-;971:32794:6;;4408:5:4;;:::i;971:32794:6:-;;;;;;;-1:-1:-1;;971:32794:6;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;;;;;10976:17;10972:45;;971:32794;;11031:15;:30;11027:63;;5388:10;971:32794;;;11031:15;11104:46;11100:77;;971:32794;;;;;;;;;;11283:10;;;:::i;:::-;971:32794;;;;;;;-1:-1:-1;971:32794:6;11336:22;;;971:32794;;;-1:-1:-1;971:32794:6;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11377:21;11413:27;;11409:586;;971:32794;;;;;;;12046:10;971:32794;;;;;;;;12042:48;;971:32794;;;;12046:10;971:32794;;;;;;;-1:-1:-1;;971:32794:6;;;;;;;12157:16;-1:-1:-1;971:32794:6;;;12157:51;;;971:32794;;-1:-1:-1;;;;;971:32794:6;;;;;;12299:76;;971:32794;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12299:76;;;;;;:::i;:::-;971:32794;;;12299:76;;;12289:87;30476:265:5;;;;;;971:32794:6;30476:265:5;12401:10:6;-1:-1:-1;;;;;971:32794:6;;12401:20;971:32794;;;;12531:84;;971:32794;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;12531:84;:::i;:::-;12530:85;12526:149;;12397:714;13142:12;12397:714;13142:12;:::i;:::-;13190:29;971:32794;;13190:29;:::i;:::-;13260:64;;;;33228:285;33469:27;33228:285;33440:25;;;971:32794;;;4858:6;;33469:27;;971:32794;;;4858:6;33228:285;;13260:64;13355:22;971:32794;13355:22;;:30;971:32794;;;;;;;-1:-1:-1;971:32794:6;;;;;-1:-1:-1;971:32794:6;;;13439:34;971:32794;;;;;;13439:34;:::i;:::-;13484:25;4858:6;971:32794;;;;;;;4858:6;;;;;;;;;;;;14021:158;;;;;;4858:6;14021:158;4858:6;14252:18;971:32794;;14252:18;:::i;:::-;4858:6;;;;;;;;-1:-1:-1;;;4858:6:6;;;;;;;;;;;;;;;;14445:36;;;14441:261;;-1:-1:-1;14739:4359:6;;;-1:-1:-1;14771:58:6;;;;;15105:30;;;4858:6;15105:30;;;;;971:32794;;;;;;;-1:-1:-1;971:32794:6;;;;4858:6;971:32794;-1:-1:-1;971:32794:6;4858:6;;971:32794;4858:6;;971:32794;;;;;;:::i;:::-;;;;;15200:41;;11031:15;971:32794;11031:15;971:32794;;;;15200:41;971:32794;;15200:41;;971:32794;;;;11336:22;971:32794;15200:41;;971:32794;;;;;;;;;;;-1:-1:-1;971:32794:6;11336:22;971:32794;;;-1:-1:-1;971:32794:6;;;4858:6;;;971:32794;;;;;4858:6;;;;;;;971:32794;4858:6;;;971:32794;4858:6;-1:-1:-1;;;;;;;4858:6:6;;-1:-1:-1;;;;;;;4858:6:6;;;;;971:32794;;;4858:6;;:::i;:::-;971:32794;;;;;;;4858:6;;;971:32794;;;;;;4858:6;;;971:32794;-1:-1:-1;;;;;971:32794:6;;;;;;;;;-1:-1:-1;;;;;;;;;;;15265:79:6;4858:6;;15265:79;971:32794;;;;;;;-1:-1:-1;971:32794:6;;;;-1:-1:-1;971:32794:6;;;;;;;;;4858:6;971:32794;4858:6;;971:32794;4858:6;971:32794;4858:6;;971:32794;;;;;;;;-1:-1:-1;;;;;;;;;;;971:32794:6;;;15367:79;;971:32794;;14767:3237;15471:57;;;;;;;;;;;;971:32794;15776:80;11336:22;971:32794;;;4858:6;971:32794;;;;;;;;;;;4858:6;971:32794;;4858:6;;15776:80;:::i;:::-;4858:6;971:32794;;;;;;;;-1:-1:-1;971:32794:6;;;;;-1:-1:-1;971:32794:6;4858:6;971:32794;;;;;;;-1:-1:-1;971:32794:6;11336:22;;;971:32794;;16046:56;971:32794;;;-1:-1:-1;971:32794:6;16046:43;:56;:::i;:::-;-1:-1:-1;;;;;971:32794:6;;-1:-1:-1;971:32794:6;;;11336:22;;;;971:32794;;;;;;;;;;16120:44;4858:6;;971:32794;11031:15;971:32794;-1:-1:-1;;4858:6:6;;;;;;971:32794;;;;;;4858:6;;;971:32794;;;;;;4858:6;;;971:32794;;;;;;;;-1:-1:-1;;;;;;;;;;;16214:79:6;4858:6;;16214:79;971:32794;;;;;;;-1:-1:-1;971:32794:6;;;;;-1:-1:-1;971:32794:6;;;;;;;;;;;;;4858:6;;971:32794;;;;4858:6;;971:32794;;;;;;;;-1:-1:-1;;;;;;;;;;;971:32794:6;;;16316:152;;971:32794;;15467:2537;971:32794;;;;;;;;;;;;;;;;;;;;4858:6;971:32794;;16997:30;971:32794;;;;;;;-1:-1:-1;971:32794:6;;;;4858:6;971:32794;-1:-1:-1;971:32794:6;4858:6;;971:32794;4858:6;;971:32794;;;;4858:6;;971:32794;;;4858:6;;;;;971:32794;;;;;;;;;;4858:6;;;971:32794;;;;;4858:6;;;971:32794;4858:6;;17490:93;;4858:6;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;-1:-1:-1;;;;;;;;;;;17064:138:6;4858:6;;17064:138;17530:24;4858:6;;;17530:24;:::i;:::-;17490:93;:::i;:::-;971:32794;;;;;;;:::i;:::-;;;;;;17654:72;;11031:15;971:32794;11031:15;971:32794;;;;17654:72;971:32794;;17654:72;;971:32794;;;;;;11336:22;971:32794;17654:72;;971:32794;;;;;;;;;;;-1:-1:-1;971:32794:6;11336:22;971:32794;;;-1:-1:-1;971:32794:6;;;4858:6;;;971:32794;;;;;4858:6;;;;;;;971:32794;4858:6;;;971:32794;4858:6;-1:-1:-1;;;;;;;4858:6:6;;-1:-1:-1;;;;;;;4858:6:6;;;;;971:32794;;;4858:6;;:::i;:::-;971:32794;;;;;;;;;4858:6;;;971:32794;;;;;4858:6;;;971:32794;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;-1:-1:-1;;;;;;;;;;;17064:138:6;4858:6;;17750:76;-1:-1:-1;;;;;971:32794:6;;;;-1:-1:-1;971:32794:6;;;;;;;;;;;;;;;;;;;;;;4858:6;;;971:32794;;;;;;4858:6;;;971:32794;;;;;;;;-1:-1:-1;;;;;;;;;;;17849:140:6;4858:6;;17849:140;971:32794;;4858:6;-1:-1:-1;;;971:32794:6;;;;;;;;14739:4359;4858:6;18142:84;;18513:229;18142:84;;;;;;;;;;;;;:::i;:::-;971:32794;;;;;;;;;;;;;;4858:6;971:32794;;;;;;;4858:6;;;;;;;18513:229;:::i;:::-;971:32794;;;;;;;;;;;:::i;:::-;;;;;11336:22;971:32794;18804:68;;11031:15;;;971:32794;;;;18804:68;;971:32794;;;;;;;18804:68;;971:32794;;;;;;;;;-1:-1:-1;971:32794:6;11336:22;971:32794;;;-1:-1:-1;971:32794:6;;;4858:6;;;971:32794;;;;;4858:6;;;;;;;971:32794;4858:6;;;971:32794;4858:6;-1:-1:-1;;;;;;;4858:6:6;;-1:-1:-1;;;;;;;4858:6:6;;;;;971:32794;;;4858:6;;:::i;:::-;971:32794;;;;;;;4858:6;;;971:32794;;;;;;4858:6;;;971:32794;-1:-1:-1;;;;;971:32794:6;;;;;;;;;-1:-1:-1;;;;;;;;;;;18892:78:6;4858:6;;18892:78;-1:-1:-1;;;;;971:32794:6;;;;-1:-1:-1;971:32794:6;;;;;;;;;;;;;;;;;;;;;;4858:6;;;971:32794;;;;;;4858:6;;;971:32794;;;;;;;;-1:-1:-1;;;;;;;;;;;18989:98:6;4858:6;;18989:98;971:32794;;14441:261;14567:22;;;;971:32794;14567:22;;14563:50;;14441:261;-1:-1:-1;;;14635:56:6;;971:32794;;;;14635:56;14563:50;14591:22;;14563:50;;4858:6;-1:-1:-1;;;971:32794:6;;;;;;;;14021:158;4858:6;14021:158;;12526:149;-1:-1:-1;;;12642:18:6;;971:32794;12936:18;12642;12397:714;971:32794;;12401:10;-1:-1:-1;;;;;971:32794:6;;;12695:32;971:32794;;;12837:72;971:32794;;;;;;;;12837:72;;;:::i;12691:420::-;-1:-1:-1;;;13085:15:6;;971:32794;13085:15;;971:32794;-1:-1:-1;;;971:32794:6;;;;;;;;12157:51;971:32794;12157:51;;;12042:48;-1:-1:-1;;;12072:18:6;;971:32794;12072:18;;11409:586;971:32794;;11460:28;971:32794;;-1:-1:-1;;;11515:17:6;;971:32794;11515:17;;11456:529;971:32794;;;11726:16;971:32794;;;;;;11688:32;11687:56;11553:432;;11456:529;;11409:586;;;;11553:432;971:32794;;;;;;;;;;;;;;;;;11031:15;971:32794;;11780:80;11776:161;;971:32794;11553:432;;;;11776:161;-1:-1:-1;;;11891:27:6;;971:32794;11891:27;;11100:77;-1:-1:-1;;;11159:18:6;;971:32794;11159:18;;11027:63;-1:-1:-1;;;11070:20:6;;971:32794;11070:20;;10972:45;-1:-1:-1;;;11002:15:6;;971:32794;11002:15;;971:32794;;;;;;;;;;;;;12478:70:3;;:::i;:::-;25304:21:6;;;;;25281:10;:49;;;;:::i;:::-;;25344:8;25340:37;;971:32794;;25340:37;-1:-1:-1;;;25361:16:6;;971:32794;;25361:16;971:32794;;;;;;;-1:-1:-1;;971:32794:6;;;;;;11745:5:4;;:::i;:::-;5250:3:6;28386:42;;28382:72;;971:32794;4858:6;28523:40;4858:6;28465:42;4858:6;971:32794;;;;;28523:40;971:32794;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;:::i;:::-;10695:219:4;;;;;971:32794:6;10695:219:4;;;;971:32794:6;;;;;;;-1:-1:-1;971:32794:6;;-1:-1:-1;;971:32794:6;;;;9762:12;971:32794;;:::i;:::-;;;9762:12;;:::i;971:32794::-;;;;;;;;;;9239:383:3;;;;;;7972:9;9132:15;971:32794:6;9239:383:3;;;;;;;;;971:32794:6;;;;;;;;;;;;;;;;;;5388:10;971:32794;;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;;;:::i;:::-;;;10695:219:4;;;;;;;;;;11280:21;:30;971:32794:6;;;;;;;-1:-1:-1;971:32794:6;;-1:-1:-1;;971:32794:6;;;;;;:::i;:::-;12478:70:3;;:::i;:::-;3082:831:4;;;;;;;;971:32794:6;;3082:831:4;;;;;;;;;;;;;;971:32794:6;;;;;;;;;-1:-1:-1;;971:32794:6;;;;25877:37;971:32794;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;25877:37;:43;971:32794;;;;;;-1:-1:-1;971:32794:6;;;;;-1:-1:-1;971:32794:6;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5554:39;971:32794;;;;;;;;-1:-1:-1;971:32794:6;;-1:-1:-1;;971:32794:6;;;;4408:5:4;971:32794:6;;10211:10:4;4408:5;:::i;971:32794:6:-;;;;;;;-1:-1:-1;;971:32794:6;;;;11745:5:4;;:::i;:::-;971:32794:6;24976:7;-1:-1:-1;;;;;971:32794:6;24976:32;;;;;971:32794;;;24976:32;971:32794;;;;;;;;;24976:32;;971:32794;;;24976:32;;971:32794;;;;;;24976:32;;;;;;;;971:32794;;24976:32;;;;:::i;:::-;;;971:32794;;24976:32;971:32794;;;;;;;;;;;24976:32;971:32794;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;4606:437:4;;;;;;971:32794:6;17016:7:4;;971:32794:6;4606:437:4;;;;;;;21302:29:6;;;21298:63;;21377:13;21392:16;;;;;;971:32794;;;21410:3;971:32794;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21496:8;;;;;:::i;:::-;971:32794;-1:-1:-1;;;;;;;;;;;;971:32794:6;;33611:45;21519:63;;21664:15;971:32794;;;;21644:35;21640:66;;971:32794;;;;;;;;;;;;;21745:14;971:32794;;;;;;;;;;-1:-1:-1;21724:53:6;21720:67;;971:32794;;21745:14;971:32794;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;-1:-1:-1;;;971:32794:6;;;;;21377:13;971:32794;21377:13;;21720:67;21779:8;;;;;;21640:66;-1:-1:-1;;;21688:18:6;;971:32794;21688:18;;21519:63;-1:-1:-1;;;21561:21:6;;971:32794;21561:21;;971:32794;-1:-1:-1;;;971:32794:6;;;;;;;;21298:63;-1:-1:-1;;;21340:21:6;;971:32794;21340:21;;4606:437:4;;;;971:32794:6;4606:437:4;;971:32794:6;;;;;;;-1:-1:-1;;971:32794:6;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;:::o;:::-;;;;-1:-1:-1;;;;;971:32794:6;;;;;;:::o;:::-;;;;-1:-1:-1;;;;;971:32794:6;;;;;;:::o;:::-;;;-1:-1:-1;;971:32794:6;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;:::o;:::-;;;;-1:-1:-1;971:32794:6;;;;;-1:-1:-1;971:32794:6;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;971:32794:6;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;971:32794:6;;;;;;;;-1:-1:-1;;971:32794:6;;;;;;;;;;;;;;20773:247;20877:1;20855:23;;20851:163;;20773:247;;;:::o;20851:163::-;971:32794;;-1:-1:-1;;;20908:32:6;;971:32794;20908:32;;;971:32794;;;20908:5;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;:::i;:::-;20908:32;;;;;;;;;;;;;;20851:163;20955:48;;;;;;971:32794;;;;;;;;;;;;;;;;;20955:48;;971:32794;20908:32;20955:48;;971:32794;;;;;;:::i;:::-;20955:48;;;;;;;;;;20773:247;;:::o;20955:48::-;;;;;:::i;:::-;20773:247;:::o;20908:32::-;;;971:32794;20908:32;;971:32794;20908:32;;;;;;971:32794;20908:32;;;:::i;:::-;;;971:32794;;;;;20908:32;;;;;;-1:-1:-1;20908:32:6;;;971:32794;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;-1:-1:-1;;971:32794:6;;;;;:::i;:::-;;;;-1:-1:-1;971:32794:6;;;;:::o;:::-;;;:::o;4858:6::-;;;;;;;:::o;:::-;971:32794;;;4858:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;971:32794::-;;-1:-1:-1;;;;;971:32794:6;;;;;;;:::o;:::-;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;:::o;4811:9::-;;971:32794;-1:-1:-1;;;;;971:32794:6;;;;;;4811:9::o;:::-;;;;;;;;;;971:32794;;;;;:::i;:::-;4811:9;;;;971:32794;;;;;;;4811:9;;;;;;;:::i;:::-;;;;;971:32794;4811:9;;;971:32794;;;;;;;;4811:9;;;;;;;971:32794;4811:9;;;:::o;:::-;971:32794;;4811:9;;;;;;;;;;;;:::o;4495:554:4:-;4606:437;;;;;;16066:7;4606:437;;;;;;;;4495:554::o;4606:437::-;;;;;;;4495:554;4606:437;;;;;;14716:7;4606:437;;;;;;;;4495:554::o;7292:355:3:-;-1:-1:-1;;7390:251:3;;;;;7292:355::o;27014:993:6:-;-1:-1:-1;971:32794:6;;;27133:11;971:32794;;;;;27173:22;;;;:28;971:32794;;;;;;;;;;;;;;;;27169:87;;27287:10;;;:::i;:::-;27452:17;971:32794;27440:9;4858:6;971:32794;;;;;;27508:7;971:32794;;;;;;27508:35;;;27133:11;27508:35;;971:32794;27508:35;;;;;;;;;;;;;;;;27014:993;-1:-1:-1;4811:9:6;-1:-1:-1;;;;;971:32794:6;;;;27691:10;:18;;;;:48;;27014:993;27687:83;;971:32794;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;27832:77;;971:32794;;;;27832:77;;971:32794;;;;27832:77;;;971:32794;;;27832:77;;;971:32794;;;;27832:77;;;971:32794;;;27781:138;;;;;971:32794;;-1:-1:-1;;;27781:138:6;;971:32794;;-1:-1:-1;;;;;971:32794:6;;;27133:11;27781:138;;971:32794;;;27508:35;971:32794;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27781:138;;971:32794;;27781:138;;;;;;;-1:-1:-1;;;;;27781:138:6;;;;;27014:993;971:32794;;;;;;;;27930:28;-1:-1:-1;971:32794:6;;;;-1:-1:-1;971:32794:6;4858:6;27014:993::o;27781:138::-;;;;;:::i;:::-;;;;971:32794;-1:-1:-1;;;971:32794:6;;;27133:11;971:32794;27508:35;971:32794;;27687:83;-1:-1:-1;;;27748:22:6;;27133:11;27748:22;;27691:48;27713:26;;;;27691:48;;27508:35;;;;;;;;;;;;;;;;;:::i;:::-;;;971:32794;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;4811:9;971:32794;;;4811:9;:::i;:::-;971:32794;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;-1:-1:-1;;;;;971:32794:6;;;;;;;;;;;;;;;;;;;;;;4811:9;971:32794;;;;27508:35;;;;;;-1:-1:-1;27508:35:6;;27169:87;-1:-1:-1;;;27229:16:6;;27133:11;27229:16;;30726:225;971:32794;;;;;;30822:15;:38;:78;;;;;30726:225;30818:127;;;30726:225::o;30818:127::-;30923:11;;;-1:-1:-1;30923:11:6;;-1:-1:-1;30923:11:6;30822:78;971:32794;;;;;;30822:15;30864:36;30822:78;;;6365:4213:5;971:32794:6;;6365:4213:5;;;;-1:-1:-1;;;;;6576:3996:5;;;;;6365:4213;;;;:::o;6576:3996::-;;;;;;;;;;971:32794:6;6576:3996:5;;;;;;;;;;;;;;;;;;971:32794:6;6576:3996:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;6576:3996:5;;;;;;;;;;;;;;971:32794:6;6576:3996:5;;;;;;;;;;971:32794:6;6576:3996:5;;;;;;;;;;;;;;;;;971:32794:6;6576:3996:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;6576:3996:5;;;971:32794:6;6576:3996:5;971:32794:6;;6576:3996:5;;;;;;;;;;;;;;;;971:32794:6;6576:3996:5;;;;;;;;;;29460:562:6;-1:-1:-1;;;;;;971:32794:6;;-1:-1:-1;;;29552:45:6;971:32794;;;;29642:14;971:32794;;;;;;;;;;;:::i;:::-;;;;;4811:9;;971:32794;;;;;;;;;;4811:9;;;971:32794;;;;;;;;;;;;29719:26;;971:32794;;29719:26;971:32794;;;;;;29719:5;971:32794;29719:26;;;;;;;971:32794;29719:26;;;29548:468;29701:15;;971:32794;29701:15;;971:32794;;;;29681:64;29677:122;;29820:40;971:32794;;;;;;;;29820:40;;:::i;:::-;29813:47;:::o;29677:122::-;29772:12;;;971:32794;29772:12;29719:26;971:32794;29772:12;971:32794;;;;;;;29719:26;971:32794;;;;29719:26;;;971:32794;29719:26;;971:32794;29719:26;;;;;;971:32794;29719:26;;;:::i;:::-;;;971:32794;;;;;29719:26;;;;;;-1:-1:-1;29719:26:6;;;971:32794;;;;;;;;;29548:468;971:32794;;-1:-1:-1;;;29924:20:6;;;;;971:32794;;;;29924:20;971:32794;29924:20;971:32794;29924:5;-1:-1:-1;;;;;971:32794:6;29924:20;;;;;;971:32794;29924:20;;;29548:468;29965:40;971:32794;;;;;;;29994:10;;971:32794;;;29965:40;;:::i;29924:20::-;;;;;;;;;;;;;:::i;:::-;;;971:32794;29924:20;971:32794;;;;;;29965:40;971:32794;;;;:::i;:::-;29924:20;;;;;;;33669:94;33746:1;33741:6;;;33746:1;;33741:15;33669:94;:::o;33741:15::-;-1:-1:-1;;;971:32794:6;;;;;33669:94;:::o;971:32794::-;-1:-1:-1;;;971:32794:6;;;;;;;;30979:1889;4858:6;30979:1889;;;;4858:6;31234:49;;971:32794;;;;;;;31330:27;;971:32794;31330:52;;4923:9;31397:43;;4923:9;;;971:32794;;4923:9;971:32794;;4858:6;;;;971:32794;31393:1469;30979:1889::o;31393:1469::-;4992:10;-1:-1:-1;4992:10:6;;;971:32794;31935:7;971:32794;;4858:6;;;;971:32794;31723:1139;30979:1889::o;31723:1139::-;971:32794;;32302:7;971:32794;;4858:6;;;971:32794;4992:10;32370:30;971:32794;4858:6;;;32439:45;4992:10;32439:45;;;;;4858:6;;;;;31723:1139;30979:1889::o;32432:247::-;4858:6;;32603:4;4858:6;;;;;;;32432:247;;;31330:52;-1:-1:-1;;31379:2:6;31330:52;;971:32794;;;;;;;;;;;;30028:692;;971:32794;;;;;;-1:-1:-1;971:32794:6;30174:22;;;971:32794;;;-1:-1:-1;971:32794:6;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30260:11;;30256:50;;4858:6;30316:22;971:32794;30642:63;30316:22;30352;971:32794;;-1:-1:-1;971:32794:6;;;;;-1:-1:-1;971:32794:6;;;;30352:39;;30348:277;971:32794;;;-1:-1:-1;971:32794:6;;;30496:40;971:32794;-1:-1:-1;971:32794:6;;;;;;;:::i;:::-;;;;;;4811:9;;;;971:32794;;;;;30174:22;971:32794;;;;;;4811:9;971:32794;;;;;;30496:40;:::i;:::-;33469:27;33228:285;33440:25;;;971:32794;;;4858:6;;33469:27;;971:32794;;;4858:6;33228:285;;30642:63;971:32794;30028:692;:::o;30348:277::-;30585:29;;;;:::i;30256:50::-;30287:8;;;-1:-1:-1;30287:8:6;:::o;6145:1089:3:-;971:32794:6;;;;;6813:405:3;;4606:437:4;6813:405:3;;;-1:-1:-1;6813:405:3;;-1:-1:-1;;6813:405:3;6145:1089::o;2952:967:4:-;3082:831;;;971:32794:6;3082:831:4;;;;;;;;;;;;;;;;;;;971:32794:6;3082:831:4;;2952:967::o;32874:348:6:-;;-1:-1:-1;;971:32794:6;;;;32993:10;33000:3;;;971:32794;;33030:59;971:32794;33076:2;971:32794;;;;;;33053:2;971:32794;;;;33030:59;:::i;32989:217::-;971:32794;;33179:2;971:32794;;33158:2;971:32794;;;;4858:6;33128:63;:::o

Swarm Source

ipfs://4bd0c5a03a900e82ca61e3b0968be7ffbaee172c0d8d5625b735d0f6e047ac90

Block Transaction Difficulty 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.