ETH Price: $2,108.41 (+1.62%)

Contract

0xaE2b1B6Dfd3CfE74E94676A6225527Be6190B197
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Distribute Exist...239335112025-12-03 14:27:59101 days ago1764772079IN
0xaE2b1B6D...e6190B197
0 ETH0.000030040.07717572
Distribute Exist...238618992025-11-23 13:30:35111 days ago1763904635IN
0xaE2b1B6D...e6190B197
0 ETH0.000043640.11210734
Distribute Exist...238618882025-11-23 13:28:23111 days ago1763904503IN
0xaE2b1B6D...e6190B197
0 ETH0.000039210.10072395
Distribute Exist...238518842025-11-22 3:41:47113 days ago1763782907IN
0xaE2b1B6D...e6190B197
0 ETH0.000053260.13681415
Distribute Exist...238518792025-11-22 3:40:35113 days ago1763782835IN
0xaE2b1B6D...e6190B197
0 ETH0.000045840.11777117
Distribute Exist...238518282025-11-22 3:30:23113 days ago1763782223IN
0xaE2b1B6D...e6190B197
0 ETH0.000035880.0921725
Distribute Exist...238518002025-11-22 3:24:47113 days ago1763781887IN
0xaE2b1B6D...e6190B197
0 ETH0.000041610.10690717
Distribute Exist...238495912025-11-21 19:56:35113 days ago1763754995IN
0xaE2b1B6D...e6190B197
0 ETH0.000147080.30978099

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x6E224Db2...1AD7B0943
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
PaymentRouterV3

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

/**
 * @title PaymentRouterV3
 * @dev FINAL PRODUCTION-READY (V3.2.9): Automatic token routing + FOT + reflection/rebasing + malicious token protection
 *
 * @notice This contract is immutable - configuration set at deployment
 * @notice All percentages must sum to exactly 100%
 * @notice Events emit amounts moved out of contract (may differ from recipient net with FOT)
 * @notice Supported tokens: ERC-20, FOT/deflationary, reflection/rebasing (best-effort)
 * @notice Recommend allowlisting tokens for production use
 * @notice V3.2.9: Added distributeExistingTokens() for automatic token routing when sent directly
 */
contract PaymentRouterV3 is ReentrancyGuard {
    using SafeERC20 for IERC20;

    // Custom errors for gas efficiency and clearer monitoring
    error ERC20OverDebit(address token, uint256 requested, uint256 moved);
    error ZeroMoveButSignalled(address token, address recipient, uint256 requested);

    // Additional custom errors for gas efficiency and consistency
    error InvalidTokenAddress();
    error NoPendingETH();
    error NoPendingTokens();
    error TokenTransferReverted();
    error ETHTransferReverted();
    error OnlyContractWallet();
    error NoETHToSweep();
    error NoTokensToSweep();

    struct Route {
        address payable wallet;
        uint256 percentage; // In basis points (10000 = 100%)
    }

    Route[] public routes;

    uint256 private constant BASIS_POINTS = 10000; // 100.00%
    uint256 private constant MAX_ROUTES = 50; // Gas safety limit

    // Gas caps for DoS protection (S-1 fix) - public for monitoring/ops visibility
    uint256 public constant ETH_SEND_GAS = 50000; // Gas limit for ETH sends (prevents DoS via gas exhaustion)
    uint256 public constant TOKEN_CALL_GAS = 120000; // Gas limit for token calls (prevents DoS via gas exhaustion)

    // Pull payment pattern
    mapping(address => uint256) public pendingETHWithdrawals;
    mapping(address => mapping(address => uint256)) public pendingTokenWithdrawals;

    // Failed transfer tracking
    uint256 public failedETHTransfers;
    mapping(address => uint256) public failedTokenTransfers;

    // Pending distribution
    uint256 public pendingDistribution;

    // Reentrancy telemetry flag
    bool private _inETHRoute;

    event PaymentReceived(address indexed from, uint256 amount);
    event PaymentReceivedDuringRoute(address indexed from, uint256 amount);
    event ETHRouted(address indexed to, uint256 amount);
    event ETHRetainedInContract(uint256 amount);
    event TokenRouted(address indexed token, address indexed to, uint256 amount);
    event TokenTransferAnomaly(address indexed token, address indexed to, uint256 attempted);

    /// @notice Emitted when tokens remain in contract after distribution
    /// @dev Reports TOTAL on-hand balance (includes locked collateral for pending withdrawals)
    /// @param token Token address
    /// @param amount Total balance remaining in contract (locked + unlocked)
    event TokenRetainedInContract(address indexed token, uint256 amount); // ✅ V2 FIX

    /// @notice Emitted when unlocked (sweepable) dust remains in contract after distribution
    /// @dev Reports only dust available for sweeping (excludes locked collateral)
    /// @param token Token address
    /// @param amount Sweepable balance (balance - failedTokenTransfers[token])
    event TokenUnlockedDust(address indexed token, uint256 amount);

    event ETHWithdrawn(address indexed to, uint256 amount);
    event TokenWithdrawn(address indexed token, address indexed to, uint256 amount);
    event TransferFailed(address indexed recipient, uint256 amount);
    event TokenTransferFailed(address indexed token, address indexed recipient, uint256 amount);
    event DistributionTriggered(uint256 amount);
    event ETHSwept(uint256 amount); // ✅ V2 FIX
    event TokenSwept(address indexed token, uint256 amount); // ✅ V2 FIX

    address public immutable contractWallet; // ✅ V2 FIX: For sweep functions

    /**
     * @dev Constructor sets up routing configuration
     * @param _routes Array of route configurations
     *
     * @notice Total percentages must equal exactly 100%
     *
     */
    constructor(Route[] memory _routes) {
        require(_routes.length > 0, "Must have at least one route");
        require(_routes.length <= MAX_ROUTES, "Too many routes");

        // CRITICAL: msg.sender becomes the immutable contractWallet
        // Verify this is the intended treasury address before deployment
        contractWallet = payable(msg.sender); // ✅ V2 FIX

        uint256 totalPercentage = 0;

        for (uint256 i = 0; i < _routes.length; i++) {
            for (uint256 j = 0; j < i; j++) {
                require(_routes[i].wallet != _routes[j].wallet, "Duplicate route wallet");
            }
            require(_routes[i].wallet != address(0), "Invalid wallet address");
            require(_routes[i].wallet != address(this), "Cannot route to self");
            require(_routes[i].wallet != contractWallet, "contractWallet cannot also be a route");
            require(_routes[i].percentage > 0, "Percentage must be greater than 0");

            totalPercentage += _routes[i].percentage;
            routes.push(_routes[i]);
        }

        require(totalPercentage == BASIS_POINTS, "Total percentage must equal exactly 100%");
    }

    /**
     * @notice Receive ETH and AUTOMATICALLY route to all recipients
     * @dev ETH is instantly distributed on every payment (automatic routing)
     * @dev FORCED ETH (S-2): ETH sent via SELFDESTRUCT bypasses receive/fallback and won't update pendingDistribution.
     *      Such forced ETH becomes sweepable via getSweepableETH (balance - pendingDistribution - failedETHTransfers).
     *      POLICY: Forced ETH is treated as treasury sweepable funds (not distributed to recipients).
     *      To include forced ETH in distributions, treasury can manually call distributeETH after reconciliation.
     */
    receive() external payable nonReentrant {
        if (_inETHRoute) {
            // Already routing - accumulate for next batch to prevent infinite recursion
            pendingDistribution += msg.value;
            emit PaymentReceivedDuringRoute(msg.sender, msg.value);
        } else {
            // AUTOMATIC ROUTING: Instantly distribute incoming payment
            emit PaymentReceived(msg.sender, msg.value);
            _routeETH(msg.value);
        }
    }

    /**
     * @dev Fallback function - AUTOMATICALLY routes incoming ETH
     */
    fallback() external payable nonReentrant {
        if (_inETHRoute) {
            // Already routing - accumulate for next batch to prevent infinite recursion
            pendingDistribution += msg.value;
            emit PaymentReceivedDuringRoute(msg.sender, msg.value);
        } else {
            // AUTOMATIC ROUTING: Instantly distribute incoming payment
            emit PaymentReceived(msg.sender, msg.value);
            _routeETH(msg.value);
        }
    }

    /**
     * @dev Manually trigger ETH distribution
     * @notice Anyone can call this to distribute accumulated ETH
     *
     */
    function distributeETH() external nonReentrant {
        uint256 amount = pendingDistribution;
        require(amount > 0, "No ETH to distribute");

        _routeETH(amount);

        // Defer-decrement: only subtract processed amount (protects against future reverts)
        // If new ETH arrived during routing (reentrancy), don't erase it
        // V3.2.7: Removed unchecked for safer future-proofing (checked math prevents mistakes)
        pendingDistribution -= amount;

        emit DistributionTriggered(amount);
    }

    /**
     * @dev Route ERC20 tokens to recipients
     * @param token The ERC20 token address
     * @param amount The amount of tokens to route
     *
     * @notice Non-standard tokens may route to pending withdrawals
     * @notice Fee-on-transfer tokens will have dust remainder
     * @notice V3.2.1 FIX: Measures actual received tokens to handle FOT on incoming transfers
     */
    function routeTokens(address token, uint256 amount) external nonReentrant {
        if (token == address(0)) revert InvalidTokenAddress();
        require(amount > 0, "Amount must be greater than 0");

        IERC20 t = IERC20(token);
        uint256 beforeBal = t.balanceOf(address(this));
        t.safeTransferFrom(msg.sender, address(this), amount);
        uint256 received = t.balanceOf(address(this)) - beforeBal;
        require(received > 0, "No tokens received");

        _routeTokens(token, received);
    }

    /**
     * @dev Distribute tokens that are already in the contract (AUTOMATIC ROUTING)
     * @param token The ERC20 token address
     *
     * @notice This function enables AUTOMATIC token routing for tokens sent directly to contract
     * @notice Anyone can call this to trigger distribution of existing token balance
     * @notice Protects locked collateral - only distributes sweepable balance
     * @notice V3.2.9: Automatic token routing support
     */
    function distributeExistingTokens(address token) external nonReentrant {
        if (token == address(0)) revert InvalidTokenAddress();

        IERC20 t = IERC20(token);
        uint256 balance = t.balanceOf(address(this));

        // Don't distribute locked collateral (pending withdrawals)
        uint256 locked = failedTokenTransfers[token];

        if (balance <= locked) revert NoPendingTokens();

        uint256 distributable = balance - locked;
        require(distributable > 0, "No tokens to distribute");

        _routeTokens(token, distributable);
    }

    /**
     * @dev Internal ETH routing logic
     * @param amount Amount to route
     *
     */
    function _routeETH(uint256 amount) private {
        if (amount == 0) return;

        _inETHRoute = true;

        uint256 remaining = amount;
        uint256 lastIndex = routes.length - 1;

        // Process all routes except last
        for (uint256 i = 0; i < lastIndex; i++) {
            uint256 share = (amount * routes[i].percentage) / BASIS_POINTS;

            if (share > 0) {
                // Reserve the share BEFORE transfer to prevent over-allocation on failure
                remaining -= share;

                (bool success, ) = routes[i].wallet.call{value: share, gas: ETH_SEND_GAS}("");

                if (success) {
                    emit ETHRouted(routes[i].wallet, share);
                } else {
                    pendingETHWithdrawals[routes[i].wallet] += share;
                    failedETHTransfers += share;
                    emit TransferFailed(routes[i].wallet, share);
                }
            }
        }

        // Send remaining to last route (handles rounding)
        if (remaining > 0) {
            (bool success, ) = routes[lastIndex].wallet.call{value: remaining, gas: ETH_SEND_GAS}("");

            if (success) {
                emit ETHRouted(routes[lastIndex].wallet, remaining);
            } else {
                pendingETHWithdrawals[routes[lastIndex].wallet] += remaining;
                failedETHTransfers += remaining;
                emit TransferFailed(routes[lastIndex].wallet, remaining);
            }
        }

        // CRITICAL: Always reset flag before exit (even though current code doesn't revert,
        // future changes must maintain this guarantee to prevent stuck state)
        _inETHRoute = false;

        // Defensive assertion: If we reach here, the function completed without revert.
        // This assertion documents the invariant and will catch future bugs if someone
        // introduces a revert path after flag set (e.g., via compiler optimizations or refactoring).
        assert(!_inETHRoute); // Should always pass since we just reset it
    }

    /**
     * @dev Internal token routing logic with FOT support
     * @param token Token address
     * @param amount Amount to route (actual received amount)
     *
     */
    function _routeTokens(address token, uint256 amount) private {
        IERC20 t = IERC20(token);
        uint256 remaining = amount;
        uint256 movedTotal = 0; // Track total actual outflow to prevent locked-collateral drain
        uint256 lastIndex = routes.length - 1;

        // Process all routes except last
        for (uint256 i = 0; i < lastIndex; i++) {
            uint256 share = (amount * routes[i].percentage) / BASIS_POINTS;
            if (share == 0) { continue; }

            // Reserve BEFORE transfer to prevent over-allocation on failure
            remaining -= share;

            uint256 beforeBal = t.balanceOf(address(this));
            (bool ok, bytes memory data) = address(t).call{gas: TOKEN_CALL_GAS}(
                abi.encodeWithSelector(t.transfer.selector, routes[i].wallet, share)
            );
            bool success = ok && (data.length == 0 || abi.decode(data, (bool)));
            uint256 afterBal = t.balanceOf(address(this));
            // Guard against malicious/rebasing tokens that could cause underflow
            uint256 moved = beforeBal > afterBal ? beforeBal - afterBal : 0;

            // Balance-delta-dominant success logic (prevents double-pay with malicious tokens)
            if (moved > 0) {
                // CRITICAL V3.2.8: Prevent adversarial over-debit
                if (moved > share) revert ERC20OverDebit(token, share, moved);

                movedTotal += moved; // Track actual outflow
                // Movement occurred: treat as success regardless of return flag
                emit TokenRouted(token, routes[i].wallet, moved);

                // Handle partial move (enqueue shortfall for pro-rata guarantee)
                if (moved < share) {
                    pendingTokenWithdrawals[routes[i].wallet][token] += (share - moved);
                    failedTokenTransfers[token] += (share - moved);
                    emit TokenTransferFailed(token, routes[i].wallet, (share - moved));
                }

                if (!success) {
                    // Token moved but signalled failure → telemetry for malicious token
                    emit TokenTransferAnomaly(token, routes[i].wallet, share);
                }
            } else if (success) {
                // Signalled success but moved 0 → reflection/rebasing anomaly, no enqueue
                emit TokenTransferAnomaly(token, routes[i].wallet, share);
            } else {
                // True failure: nothing moved and signalled failure → enqueue
                pendingTokenWithdrawals[routes[i].wallet][token] += share;
                failedTokenTransfers[token] += share;
                emit TokenTransferFailed(token, routes[i].wallet, share);
            }
        }

        if (remaining > 0) {
            uint256 toAttempt = remaining;
            uint256 beforeBal2 = t.balanceOf(address(this));
            (bool ok2, bytes memory data2) = address(t).call{gas: TOKEN_CALL_GAS}(
                abi.encodeWithSelector(t.transfer.selector, routes[lastIndex].wallet, toAttempt)
            );
            bool success2 = ok2 && (data2.length == 0 || abi.decode(data2, (bool)));
            uint256 afterBal2 = t.balanceOf(address(this));
            // Guard against malicious/rebasing tokens that could cause underflow
            uint256 moved2 = beforeBal2 > afterBal2 ? beforeBal2 - afterBal2 : 0;

            // Balance-delta-dominant success logic (prevents double-pay with malicious tokens)
            if (moved2 > 0) {
                // CRITICAL V3.2.8: Prevent adversarial over-debit
                if (moved2 > toAttempt) revert ERC20OverDebit(token, toAttempt, moved2);

                movedTotal += moved2; // Track actual outflow
                // Movement occurred: treat as success regardless of return flag
                emit TokenRouted(token, routes[lastIndex].wallet, moved2);

                // Handle partial move (enqueue shortfall for pro-rata guarantee)
                if (moved2 < toAttempt) {
                    pendingTokenWithdrawals[routes[lastIndex].wallet][token] += (toAttempt - moved2);
                    failedTokenTransfers[token] += (toAttempt - moved2);
                    emit TokenTransferFailed(token, routes[lastIndex].wallet, (toAttempt - moved2));
                }

                if (!success2 || moved2 != toAttempt) {
                    // Token moved but signalled failure OR partial move → telemetry
                    emit TokenTransferAnomaly(token, routes[lastIndex].wallet, toAttempt);
                }
            } else if (success2) {
                // Signalled success but moved 0 → reflection/rebasing anomaly, no enqueue
                emit TokenTransferAnomaly(token, routes[lastIndex].wallet, toAttempt);
            } else {
                // True failure: nothing moved and signalled failure → enqueue
                pendingTokenWithdrawals[routes[lastIndex].wallet][token] += toAttempt;
                failedTokenTransfers[token] += toAttempt;
                emit TokenTransferFailed(token, routes[lastIndex].wallet, toAttempt);
            }
        }

        // After all transfers, emit retained event if dust remains
        // (Can happen with broken tokens that return true but move 0)
        uint256 dust = t.balanceOf(address(this));
        if (dust > 0) {
            emit TokenRetainedInContract(token, dust);
        }

        // Emit unlocked dust separately for operational clarity
        // (Prevents confusion between "retained" which includes locked queues vs "sweepable")
        uint256 locked = failedTokenTransfers[token];
        uint256 unlocked = dust > locked ? (dust - locked) : 0;
        if (unlocked > 0) {
            emit TokenUnlockedDust(token, unlocked);
        }
    }

    /**
     * @dev Withdraw pending ETH (pull payment)
     */
    function withdrawPendingETH() external nonReentrant {
        uint256 amount = pendingETHWithdrawals[msg.sender];
        if (amount == 0) revert NoPendingETH();

        pendingETHWithdrawals[msg.sender] = 0;
        failedETHTransfers -= amount;

        (bool success, ) = payable(msg.sender).call{value: amount}("");
        if (!success) revert ETHTransferReverted();

        emit ETHWithdrawn(msg.sender, amount);
    }

    /**
     * @dev Withdraw pending tokens (pull payment)
     */
    function withdrawPendingTokens(address token) external nonReentrant {
        if (token == address(0)) revert InvalidTokenAddress();
        uint256 amount = pendingTokenWithdrawals[msg.sender][token];
        if (amount == 0) revert NoPendingTokens();

        IERC20 t = IERC20(token);
        uint256 beforeBal = t.balanceOf(address(this));

        (bool ok, bytes memory data) = address(t).call{gas: TOKEN_CALL_GAS}(
            abi.encodeWithSelector(t.transfer.selector, msg.sender, amount)
        );
        bool signalled = ok && (data.length == 0 || abi.decode(data, (bool)));
        uint256 afterBal = t.balanceOf(address(this));
        uint256 moved = beforeBal > afterBal ? beforeBal - afterBal : 0;

        if (moved > 0) {
            // CRITICAL V3.2.8: Prevent adversarial over-debit
            if (moved > amount) revert ERC20OverDebit(token, amount, moved);

            // Compute residual and update bookkeeping precisely
            uint256 residual = amount - moved;

            // Update per-recipient queue (keeps residual for partial pays)
            pendingTokenWithdrawals[msg.sender][token] = residual;

            // Update global failure pool by actual movement only
            failedTokenTransfers[token] -= moved;

            emit TokenWithdrawn(token, msg.sender, moved);

            // Telemetry for anomalies (success flag mismatch or partial move)
            if (!signalled || moved != amount) {
                emit TokenTransferAnomaly(token, msg.sender, amount);
            }
        } else if (signalled) {
            // Claimed success but moved 0: keep claim intact
            emit TokenTransferAnomaly(token, msg.sender, amount);
            revert ZeroMoveButSignalled(token, msg.sender, amount);
        } else {
            revert TokenTransferReverted();
        }
    }

    /**
     * @dev Sweep retained ETH to contract wallet
     *
     * @notice Only contract wallet can call
     * @notice Sweeps ETH not allocated to distributions or pending withdrawals
     */
    function sweepETH() external nonReentrant {
        if (msg.sender != contractWallet) revert OnlyContractWallet();

        uint256 balance = address(this).balance;
        uint256 locked = pendingDistribution + failedETHTransfers;

        if (balance <= locked) revert NoETHToSweep();

        uint256 sweepable = balance - locked;

        (bool success, ) = contractWallet.call{value: sweepable, gas: ETH_SEND_GAS}("");
        if (!success) revert ETHTransferReverted();

        emit ETHSwept(sweepable);
    }

    /**
     * @dev Sweep retained tokens to contract wallet
     * ✅ V2 CRITICAL FIX: Prevents permanent fund lockup
     *
     * @param token Token address to sweep
     * @notice Only contract wallet can call
     * @notice Sweeps tokens not allocated to pending withdrawals
     */
    function sweepTokens(address token) external nonReentrant {
        if (msg.sender != contractWallet) revert OnlyContractWallet();
        if (token == address(0)) revert InvalidTokenAddress();

        IERC20 t = IERC20(token);
        uint256 balance = t.balanceOf(address(this));
        uint256 locked = failedTokenTransfers[token];

        if (balance <= locked) revert NoTokensToSweep();

        uint256 sweepable = balance - locked;

        uint256 beforeBal = t.balanceOf(address(this));
        (bool ok, bytes memory data) = address(t).call{gas: TOKEN_CALL_GAS}(
            abi.encodeWithSelector(t.transfer.selector, contractWallet, sweepable)
        );
        bool signalled = ok && (data.length == 0 || abi.decode(data, (bool)));
        uint256 afterBal = t.balanceOf(address(this));
        uint256 moved = beforeBal > afterBal ? beforeBal - afterBal : 0;

        if (moved > 0) {
            // CRITICAL V3.2.8: Prevent adversarial over-debit
            if (moved > sweepable) revert ERC20OverDebit(token, sweepable, moved);

            emit TokenSwept(token, moved);
            if (!signalled || moved != sweepable) {
                emit TokenTransferAnomaly(token, contractWallet, sweepable);
            }
        } else if (signalled) {
            emit TokenTransferAnomaly(token, contractWallet, sweepable);
            revert ZeroMoveButSignalled(token, contractWallet, sweepable);
        } else {
            revert TokenTransferReverted();
        }
    }

    /**
     * @dev Get route count
     */
    function getRoutesCount() external view returns (uint256) {
        return routes.length;
    }

    /**
     * @dev Get route details
     */
    function getRoute(uint256 index) external view returns (
        address wallet,
        uint256 percentage
    ) {
        require(index < routes.length, "Index out of bounds");
        Route memory route = routes[index];
        return (route.wallet, route.percentage);
    }

    /**
     * @dev Get all routes
     */
    function getAllRoutes() external view returns (Route[] memory) {
        return routes;
    }

    /**
     * @dev Check pending ETH for address
     */
    function getPendingETH(address account) external view returns (uint256) {
        return pendingETHWithdrawals[account];
    }

    /**
     * @dev Check pending tokens for address
     */
    function getPendingTokens(address account, address token) external view returns (uint256) {
        return pendingTokenWithdrawals[account][token];
    }

    /**
     * @dev Get pending distribution amount
     */
    function getPendingDistribution() external view returns (uint256) {
        return pendingDistribution;
    }

    /**
     * @dev Get sweepable ETH amount
     * @notice Amount that can be swept (retained funds)
     */
    function getSweepableETH() external view returns (uint256) {
        uint256 balance = address(this).balance;
        uint256 locked = pendingDistribution + failedETHTransfers;
        return balance > locked ? balance - locked : 0;
    }

    /**
     * @dev Get sweepable token amount
     * @param token Token address
     * @notice Amount that can be swept (retained funds)
     */
    function getSweepableTokens(address token) external view returns (uint256) {
        if (token == address(0)) revert InvalidTokenAddress();
        uint256 balance = IERC20(token).balanceOf(address(this));
        uint256 locked = failedTokenTransfers[token];
        return balance > locked ? balance - locked : 0;
    }

    /**
     * @dev Get unlocked token balance (operational monitoring helper)
     * @param token Token address
     * @return amount Tokens not locked in pull-payment queue (same as getSweepableTokens)
     *
     */
    function getUnlockedTokenBalance(address token) external view returns (uint256) {
        if (token == address(0)) revert InvalidTokenAddress();
        uint256 balance = IERC20(token).balanceOf(address(this));
        uint256 locked = failedTokenTransfers[token];
        return balance > locked ? balance - locked : 0;
    }

    /**
     * @dev DEBUG/AUDIT HELPER: Verify Token Queue Consistency Invariant
     * @param token Token address to check
     * @param accounts Array of all route addresses that may have pending tokens
     * @return totalPending Sum of all individual pending token withdrawals
     * @return globalPool Value of failedTokenTransfers[token]
     * @return consistent True if totalPending == globalPool (invariant holds)
     *
     */
    function verifyTokenQueueInvariant(address token, address[] calldata accounts)
        external
        view
        returns (uint256 totalPending, uint256 globalPool, bool consistent)
    {
        if (token == address(0)) revert InvalidTokenAddress();

        totalPending = 0;
        for (uint256 i = 0; i < accounts.length; i++) {
            totalPending += pendingTokenWithdrawals[accounts[i]][token];
        }

        globalPool = failedTokenTransfers[token];
        consistent = (totalPending == globalPool);

        return (totalPending, globalPool, consistent);
    }

    /**
     * @dev DEBUG/AUDIT HELPER: Verify ETH Queue Consistency Invariant
     * @param accounts Array of all route addresses that may have pending ETH
     * @return totalPending Sum of all individual pending ETH withdrawals
     * @return globalPool Value of failedETHTransfers
     * @return consistent True if totalPending == globalPool (invariant holds)
     *
     */
    function verifyETHQueueInvariant(address[] calldata accounts)
        external
        view
        returns (uint256 totalPending, uint256 globalPool, bool consistent)
    {
        totalPending = 0;
        for (uint256 i = 0; i < accounts.length; i++) {
            totalPending += pendingETHWithdrawals[accounts[i]];
        }

        globalPool = failedETHTransfers;
        consistent = (totalPending == globalPool);

        return (totalPending, globalPool, consistent);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

File 3 of 8 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";

File 4 of 8 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

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

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"components":[{"internalType":"address payable","name":"wallet","type":"address"},{"internalType":"uint256","name":"percentage","type":"uint256"}],"internalType":"struct PaymentRouterV3.Route[]","name":"_routes","type":"tuple[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"moved","type":"uint256"}],"name":"ERC20OverDebit","type":"error"},{"inputs":[],"name":"ETHTransferReverted","type":"error"},{"inputs":[],"name":"InvalidTokenAddress","type":"error"},{"inputs":[],"name":"NoETHToSweep","type":"error"},{"inputs":[],"name":"NoPendingETH","type":"error"},{"inputs":[],"name":"NoPendingTokens","type":"error"},{"inputs":[],"name":"NoTokensToSweep","type":"error"},{"inputs":[],"name":"OnlyContractWallet","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TokenTransferReverted","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"ZeroMoveButSignalled","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DistributionTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ETHRetainedInContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ETHRouted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ETHSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ETHWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PaymentReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PaymentReceivedDuringRoute","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenRetainedInContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenRouted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"attempted","type":"uint256"}],"name":"TokenTransferAnomaly","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenTransferFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenUnlockedDust","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferFailed","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"ETH_SEND_GAS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_CALL_GAS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"distributeETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"distributeExistingTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"failedETHTransfers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"failedTokenTransfers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllRoutes","outputs":[{"components":[{"internalType":"address payable","name":"wallet","type":"address"},{"internalType":"uint256","name":"percentage","type":"uint256"}],"internalType":"struct PaymentRouterV3.Route[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingDistribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getPendingETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"getPendingTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoute","outputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"percentage","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRoutesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSweepableETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getSweepableTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getUnlockedTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingDistribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pendingETHWithdrawals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"pendingTokenWithdrawals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"routeTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"routes","outputs":[{"internalType":"address payable","name":"wallet","type":"address"},{"internalType":"uint256","name":"percentage","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sweepETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"sweepTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"verifyETHQueueInvariant","outputs":[{"internalType":"uint256","name":"totalPending","type":"uint256"},{"internalType":"uint256","name":"globalPool","type":"uint256"},{"internalType":"bool","name":"consistent","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"verifyTokenQueueInvariant","outputs":[{"internalType":"uint256","name":"totalPending","type":"uint256"},{"internalType":"uint256","name":"globalPool","type":"uint256"},{"internalType":"bool","name":"consistent","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawPendingETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"withdrawPendingTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

0x604060a081523462000518576200277390813803806200001f8162000548565b9384398201916020908181850312620005185780516001600160401b03918282116200051857019084601f83011215620005185781519080821162000532576200006e848360051b0162000548565b95848088858152019360061b8501019381851162000518578501925b848410620004cc578787876001926000848155815115620004885760329485835111620004525760809533875282938284905b62000148575b505050505061271003620000f55750516121b39182620005c083395181818161030a015281816109e60152610b0f0152f35b608491519062461bcd60e51b82526004820152602860248201527f546f74616c2070657263656e74616765206d75737420657175616c2065786163604482015267746c79203130302560c01b6064820152fd5b81518110156200044c57845b818110620003af57506001600160a01b03958662000173838562000594565b515116156200036b5730876200018a848662000594565b51511614620003275786620001a0838562000594565b515116878b511614620002d55787620001ba838562000594565b51015115620002875787620001d0838562000594565b5101518101809111620002735795620001ea828462000594565b518554680100000000000000008110156200025f578681018088558110156200024b57868852898820825191881b0180546001600160a01b03191691909316178255880151908501558392919062000242906200056e565b909192620000bd565b634e487b7160e01b88526004869052602488fd5b634e487b7160e01b88526041600452602488fd5b634e487b7160e01b86526011600452602486fd5b885162461bcd60e51b815260048101899052602160248201527f50657263656e74616765206d7573742062652067726561746572207468616e206044820152600360fc1b6064820152608490fd5b885162461bcd60e51b815260048101899052602560248201527f636f6e747261637457616c6c65742063616e6e6f7420616c736f206265206120604482015264726f75746560d81b6064820152608490fd5b885162461bcd60e51b815260048101899052601460248201527f43616e6e6f7420726f75746520746f2073656c660000000000000000000000006044820152606490fd5b885162461bcd60e51b815260048101899052601660248201527f496e76616c69642077616c6c65742061646472657373000000000000000000006044820152606490fd5b94989097909693959394929391926001600160a01b0380620003d28b8762000594565b51511690620003e2838762000594565b515116146200040857620003f6906200056e565b98949698979097959392919562000154565b815162461bcd60e51b815260048101879052601660248201527f4475706c696361746520726f7574652077616c6c6574000000000000000000006044820152606490fd5b620000c3565b845162461bcd60e51b815260048101859052600f60248201526e546f6f206d616e7920726f7574657360881b6044820152606490fd5b835162461bcd60e51b815260048101849052601c60248201527f4d7573742068617665206174206c65617374206f6e6520726f757465000000006044820152606490fd5b86848303126200051857865190878201828110858211176200051d5788528451906001600160a01b038216820362000518578288928a945282870151838201528152019301926200008a565b600080fd5b60246000634e487b7160e01b81526041600452fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f191682016001600160401b038111838210176200053257604052565b60001981146200057e5760010190565b634e487b7160e01b600052601160045260246000fd5b8051821015620005a95760209160051b010190565b634e487b7160e01b600052603260045260246000fdfe608060408181526004918236101561003a575b50505036156100325761002361151b565b61002b61149c565b6001600055005b61002361151b565b600090813560e01c9081630134aeba146112d657508063078ba1d41461123f5780631f69692414611139578063432994bf146110f05780634c6f7c77146110b85780634e9beead146110b85780636a2239e114610e9e5780636bd3470e14610d37578063726f16d814610e505780639275184414610e185780639c22b9a614610df95780639c4df63614610d5b5780639cc72f7f14610d3c578063a0a9a85d14610d37578063a28ece7214610c04578063aecf9f8f14610ab1578063b8b9b54914610b5c578063c8b664c914610b3e578063c8e706e214610afa578063cdca2bd314610ab1578063d47f6877146109c9578063db16c12a146109ab578063dcbe32e6146106a0578063ee51273b1461067f578063f5f6d3af146102d9578063fa66358a146102485763fde728a5036100125734610245578160031936011261024557610184611328565b9260243567ffffffffffffffff8111610241576101a490369083016112f2565b946001600160a01b0390811692831561023357509490839584925b8084106101eb57848652600560209081528787205488518a815291820181905289146040820152606090f35b9091929661022561022b918461020a6102058c878a612119565b612129565b16885260206003815289892090888a52528888205490611479565b97611583565b9291906101bf565b8551630f58058360e11b8152fd5b8280fd5b80fd5b5082903461024557602036600319011261024557508035906001548210156102a0575061027761027d91611429565b506120e1565b805160209182015192516001600160a01b03909116815290810191909152604090f35b606490602084519162461bcd60e51b83528201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152fd5b50919034610241576020908160031936011261067b576102f7611328565b9161030061151b565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008181169591338790036106685785169485156106585784516370a0823160e01b8082523085830152919085816024818b5afa90811561064e578a9161061d575b50878a5260058652868a2054908181111561060d57906103889161153e565b938651838152308282015286816024818c5afa908115610603578b916105d2575b50875163a9059cbb60e01b8882019081526001600160a01b0387166024830152604482018890528c918291906103ec81606481015b03601f19810183528261154b565b5190828d6201d4c0f1936103fe6115a5565b8561059f575b508851908152308382015287816024818d5afa908115610595578c91610564575b508082111561055b576104379161153e565b935b84156104f257508484116104ba5750508290867fe501bb37b6bef3426625fab8c3a24d8b13c03875431d7da0ac09609ce80d1f4c868851868152a2159182156104af575b5050610490575b50505050506001815580f35b60008051602061213e8339815191529251908152a33880808080610484565b14159050813861047d565b8651633624588160e21b81526001600160a01b03909216908201908152602081018590526040810184905281906060010390fd5b0390fd5b8590888b8b8a9760001461054b5760008051602061213e8339815191526104ee9697988451878152a35163c43b2e7760e01b81526001600160a01b03958616948101948552941660208401526040830152829160600190565b825163012a6c6b60e51b81528690fd5b50508993610439565b90508781813d831161058e575b61057b818361154b565b8101031261058a575138610425565b8b80fd5b503d610571565b89513d8e823e3d90fd5b8091955051908882159283156105ba575b5050509338610404565b6105ca935082018101910161182c565b3888816105b0565b90508681813d83116105fc575b6105e9818361154b565b810103126105f85751386103a9565b8a80fd5b503d6105df565b88513d8d823e3d90fd5b875163117ddeb560e11b81528690fd5b90508581813d8311610647575b610634818361154b565b81010312610643575138610369565b8980fd5b503d61062a565b87513d8c823e3d90fd5b8451630f58058360e11b81528390fd5b845160016210ee1d60e01b031981528390fd5b8380fd5b50903461069c578160031936011261069c576020905161c3508152f35b5080fd5b509134610241576020918260031936011261067b576106bd611328565b926106c661151b565b6001600160a01b03841692831561099d573386526003825282862084875282528286205494851561098e5783516370a0823160e01b8082523084830152919084816024818a5afa908115610984578991610953575b50855163a9059cbb60e01b868201908152336024830152604482018a90528a9182919061074b81606481016103de565b5190828b6201d4c0f19261075d6115a5565b84610920575b508651908152308582015285816024818b5afa90811561064e578a916108f3575b50808211156108ea576107969161153e565b925b831561087f5787841161084b57505085906107b3838361153e565b33895260038552858920878a52855285892055600584528488206107d884825461153e565b90558451838152867f8210728e7c071f615b840ee026032693858fbcd5e5359e67e438c890f59e5620863393a315918215610840575b5050610820575b505050506001815580f35b60008051602061213e83398151915291519384523393a338808080610815565b14159050843861080e565b8551633624588160e21b81526001600160a01b03909216908201908152602081018890526040810184905281906060010390fd5b868289888887156108da576104ee939460008051602061213e8339815191528351928584523393a35163c43b2e7760e01b81526001600160a01b03909316938301938452336020850152604084015290918291606090910190565b815163012a6c6b60e51b81528690fd5b50508792610798565b90508581813d8311610919575b61090a818361154b565b81010312610643575138610784565b503d610900565b80919450519086821592831561093b575b5050509238610763565b61094b935082018101910161182c565b388681610931565b90508481813d831161097d575b61096a818361154b565b8101031261097957513861071b565b8880fd5b503d610960565b86513d8b823e3d90fd5b5082516348d555c760e01b8152fd5b8251630f58058360e11b8152fd5b50903461069c578160031936011261069c57602090516201d4c08152f35b509190346102415782600319360112610241576109e461151b565b7f0000000000000000000000000000000000000000000000000000000000000000916001600160a01b0383163303610aa05747610a25600654835490611479565b9081811115610a90578580610a3c8194829461153e565b809761c350f1610a4a6115a5565b5015610a8257507f19b11090832956cdfe240feac6797d3886fbd25a8263687a67dff619e4a809989160209151908152a16001815580f35b90516338e81ea760e21b8152fd5b83516326c6886560e21b81528390fd5b905160016210ee1d60e01b03198152fd5b50903461069c578060031936011261069c5780602092610acf611328565b610ad761133e565b6001600160a01b0391821683526003865283832091168252845220549051908152f35b50903461069c578160031936011261069c57517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50913461024157826003193601126102415760209250549051908152f35b50919034610241578260031936011261024157610b7761151b565b600654918215610bcb575081602091610bb07f01d5a1e370499ab5939b7a1e819bccfcfd648d33bbdcef2c8b035b211af2c2f1946115e5565b610bbc8260065461153e565b60065551908152a16001815580f35b6020606492519162461bcd60e51b835282015260146024820152734e6f2045544820746f206469737472696275746560601b6044820152fd5b50823461069c576020908160031936011261024157610c21611328565b90610c2a61151b565b6001600160a01b0382168015610d285785516370a0823160e01b81523083820152908482602481845afa918215610d1e578692610ceb575b50855260058452858520549081811115610cdb5790610c809161153e565b928315610c995784610c928585611844565b6001815580f35b855162461bcd60e51b815291820152601760248201527f4e6f20746f6b656e7320746f2064697374726962757465000000000000000000604482015260649150fd5b86516348d555c760e01b81528390fd5b9091508481813d8311610d17575b610d03818361154b565b81010312610d1357519087610c62565b8580fd5b503d610cf9565b87513d88823e3d90fd5b508451630f58058360e11b8152fd5b611354565b50903461069c578160031936011261069c576020906001549051908152f35b50919034610241578260031936011261024157610d7661151b565b338352600260205280832054918215610deb5733845260026020528382812055610da183825461153e565b81558380808086335af1610db36115a5565b5015610a825750519081527f94b2de810873337ed265c5f8cf98c9cffefa06b8607f9a2f1fbaebdfbcfbef1c60203392a26001815580f35b9051630a73f65f60e21b8152fd5b50903461069c578160031936011261069c576020906006549051908152f35b50903461069c57602036600319011261069c5760209181906001600160a01b03610e40611328565b1681526005845220549051908152f35b50823461069c57602036600319011261069c5735906001548210156102455750610e7990611429565b50805460019091015491516001600160a01b0390911681526020810191909152604090f35b50823461069c578260031936011261069c57610eb8611328565b602491823592610ec661151b565b6001600160a01b03831680156110a85784156110665786516370a0823160e01b808252308583015260209687838681875afa92831561105c5788918a918295611028575b508b516323b872dd60e01b84820190815233898301908152306020820152604081019390935291610f3f9082906060016103de565b519082875af115610fff5787513d61101f5750823b155b611009578690848a5180958193825230898301525afa8015610fff578790610fca575b610f83925061153e565b938415610f955785610c928686611844565b865162461bcd60e51b81529283015260129082015271139bc81d1bdad95b9cc81c9958d95a5d995960721b6044820152606490fd5b50908581813d8311610ff8575b610fe1818361154b565b81010312610ff45790610f839151610f79565b8680fd5b503d610fd7565b88513d89823e3d90fd5b8851635274afe760e01b81528086018490528490fd5b60011415610f56565b92839195508092503d8311611055575b611042818361154b565b810103126109795788889151938c610f0a565b503d611038565b8a513d8b823e3d90fd5b865162461bcd60e51b8152602081850152601d818401527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606490fd5b8651630f58058360e11b81528390fd5b50903461069c57602036600319011261069c5760209181906001600160a01b036110e0611328565b1681526002845220549051908152f35b509134610241578260031936011261024157916020926111164791600654905490611479565b908181111561113157611129925061153e565b905b51908152f35b50509061112b565b5082903461024557806003193601126102455760019081549267ffffffffffffffff841161122c575083929193519360209461117a868560051b018261154b565b83815281835285810193837fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6865b8383106112015750505050845195869581870192828852518093528087019594905b8382106111d75787870388f35b855180516001600160a01b03168852830151878401528897509586019594820194908401906111ca565b9460028a82999a9b97611216859a989a6120e1565b81520192019201919098979694989593956111a8565b634e487b7160e01b825260419052602490fd5b509134610241576020928360031936011261024557813567ffffffffffffffff811161069c5761127290369084016112f2565b9091809581935b83851061129b5785548751898152602081018290529089146040820152606090f35b90919293966102256112cd9160018060a01b036112bc6102058c8a88612119565b168652600285528886205490611479565b93929190611279565b90503461069c578160031936011261069c576020906006548152f35b9181601f840112156113235782359167ffffffffffffffff8311611323576020808501948460051b01011161132357565b600080fd5b600435906001600160a01b038216820361132357565b602435906001600160a01b038216820361132357565b3461132357602080600319360112611323576001600160a01b03611376611328565b168015611417576040516370a0823160e01b8152306004820152908282602481845afa91821561140b576000926113dc575b50600052600582526040600020546000918181116000146113d5576113cd925061153e565b604051908152f35b50506113cd565b90918382813d8311611404575b6113f3818361154b565b8101031261024557505190386113a8565b503d6113e9565b6040513d6000823e3d90fd5b604051630f58058360e11b8152600490fd5b60015481101561146357600160005260011b7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60190600090565b634e487b7160e01b600052603260045260246000fd5b9190820180921161148657565b634e487b7160e01b600052601160045260246000fd5b60075460ff16156114e4576114b334600654611479565b6006556040513481527fd206448f7b56e8ac6ea4c25d631698548c420690635c4f1ec3ea85f768cea1cf60203392a2565b6040513481527f6ef95f06320e7a25a04a175ca677b7052bdd97131872c2192525a629f51be77060203392a2611519346115e5565b565b60026000541461152c576002600055565b604051633ee5aeb560e01b8152600490fd5b9190820391821161148657565b90601f8019910116810190811067ffffffffffffffff82111761156d57604052565b634e487b7160e01b600052604160045260246000fd5b60001981146114865760010190565b8181029291811591840414171561148657565b3d156115e0573d9067ffffffffffffffff821161156d57604051916115d4601f8201601f19166020018461154b565b82523d6000602084013e565b606090565b801561182957600160ff199181836007541617600755809180549160001983019283116114865760005b83811061170a575050508161162a575b505060075416600755565b61163381611429565b509060008080808660018060a01b038097541661c350f16116526115a5565b5015611698577f3202aa65eac199b43dfb2dbcaaea2d51df13baa8a0282f3d13fb2381a4187fb591611685602092611429565b50541692604051908152a25b388061161f565b816116fa827f1c43b9761b3fba5321ca8212bfc231945f668ccc0c446f333999eea9ce8fda81946116ca602095611429565b5054166000526002845260406000206116e4878254611479565b90556116f286600454611479565b600455611429565b50541692604051908152a2611691565b6127106117238461171a84611429565b50015484611592565b0480611739575b5061173490611583565b61160f565b9490611748866117349361153e565b9561175282611429565b5060008080808560018060a01b038096541661c350f16117706115a5565b50156117b55760207f3202aa65eac199b43dfb2dbcaaea2d51df13baa8a0282f3d13fb2381a4187fb5916117a385611429565b50541692604051908152a25b9061172a565b907f1c43b9761b3fba5321ca8212bfc231945f668ccc0c446f333999eea9ce8fda8190826117e285611429565b5054166000526020906002825260409384600020611801838254611479565b90556004611810838254611479565b905561181b86611429565b5054169351908152a26117af565b50565b90816020910312611323575180151581036113235790565b9080600090600180549160001983019283116120cd57835b838110611cef575050508261196f575b50506040516370a0823160e01b81523060048201526001600160a01b0390921691602091508181602481865afa90811561140b57600091611942575b5080611913575b826000526005825260406000205460009181811160001461190b576118d4925061153e565b905b816118e057505050565b7f69daea1f10f0159fc50d869130336ad6f2803f97957a5113415a3c98338d0c0591604051908152a2565b5050906118d6565b827f2e7c052eb4d23d62b74d28ad223e3e160e10279f69c7c38910c945ee1797a2bf83604051848152a26118af565b908282813d8311611968575b611958818361154b565b81010312610245575051386118a8565b503d61194e565b604080516370a0823160e01b80825230600483015291946001600160a01b038781169560209492939192909185816024818b5afa908115611ce457600091611cb7575b50600080856119c08a611429565b50548c5163a9059cbb60e01b8b8201908152929091166001600160a01b03166024820152604481018990526119f881606481016103de565b5190828c6201d4c0f191611a0a6115a5565b83611c84575b50895190815230600482015286816024818c5afa908115611c7957600091611c4c575b5060009181811115611c4457611a49925061153e565b915b8215611bb657848311611b885790611a64838693611479565b5083611a6f88611429565b505416887fbc4928bea7c4dad9c3e119c0eeb09bc569f266709f76666d74f34ef1441aefa6888c51878152a3818310611af9575b15918215611aee575b5050611ac2575b5050505050505b38808061186c565b611ada60008051602061213e83398151915294611429565b5054169451908152a3388080808080611ab3565b141590508238611aac565b611b03838361153e565b84611b0d89611429565b5054166000526003875289600020896000528752611b308a600020918254611479565b9055611b3c838361153e565b8860005260058752611b538a600020918254611479565b905583611b5f88611429565b5054168860008051602061215e83398151915288611b7d878761153e565b8d51908152a3611aa3565b8851633624588160e21b81526001600160a01b038b1660048201526024810186905260448101849052606490fd5b50159050611be457611bd660008051602061213e83398151915294611429565b5054169451908152a3611aba565b611bd68482611c0160008051602061215e83398151915297611429565b505416600052600385528760002087600052855287600020611c24858254611479565b9055866000526005855287600020611c3d858254611479565b9055611429565b505091611a4b565b908782813d8311611c72575b611c62818361154b565b8101031261024557505138611a33565b503d611c58565b8a513d6000823e3d90fd5b809193505190878215928315611c9f575b5050509138611a10565b611caf935082018101910161182c565b388781611c95565b908682813d8311611cdd575b611ccd818361154b565b81010312610245575051386119b2565b503d611cc3565b89513d6000823e3d90fd5b612710611d028461171a84999899611429565b049485156120c15785611d149161153e565b9560409081516370a0823160e01b90818152600498308a83015260018060a01b0392838d1694602093602492858285818b5afa918215611ce4578e918986888d8f8d908d9760009a612067575b5092611dae60009694936103de88979594611d7c8996611429565b50541691519384928c84019763a9059cbb60e01b8952840160209093929193604081019460018060a01b031681520152565b51926201d4c0f195611dbe6115a5565b87612034575b508b5193849283523090830152818b5afa908115611ce457600091612007575b5060009181811115611fff57611dfa925061153e565b9b5b8c15611f6557838d11611f2f575090611e1e8c611e6e99989796959493611479565b9b84611e2989611429565b505416867fbc4928bea7c4dad9c3e119c0eeb09bc569f266709f76666d74f34ef1441aefa6868a51858152a3828110611e9f575b5015611e73575b5050505050611583565b61185c565b60008051602061213e83398151915292611e8c87611429565b5054169451908152a33880808080611e64565b611ea9818461153e565b85611eb38a611429565b5054166000526003855287600020876000528552611ed688600020918254611479565b9055611ee2818461153e565b8660005260058552611ef988600020918254611479565b90558560008051602061215e83398151915285611f2388611f198d611429565b505416948761153e565b8a51908152a338611e5d565b8e906104ee8e868b51948594633624588160e21b86528501604091949392606082019560018060a01b0316825260208201520152565b509a50611e6e9695949392919015611f9e5760008051602061213e83398151915292611f9087611429565b5054169451908152a3611583565b8260008051602061215e83398151915293611fb888611429565b505416600052600383528560002085600052835285600020611fdb838254611479565b9055846000526005835285600020611ff4838254611479565b9055611f9087611429565b50509b611dfc565b908682813d831161202d575b61201d818361154b565b8101031261024557505138611de4565b503d612013565b80919750519083821592831561204f575b5050509538611dc4565b61205f935082018101910161182c565b388381612045565b9850505050505050929082813d83116120ba575b612085818361154b565b810103126102455750858a928f9260008b88828f611dae8f916103de8f93611d7c869a519e95989a5050945050939550611d61565b503d61207b565b959450611e6e90611583565b634e487b7160e01b84526011600452602484fd5b906040516040810181811067ffffffffffffffff82111761156d5760405282546001600160a01b031681526001909201546020830152565b91908110156114635760051b0190565b356001600160a01b0381168103611323579056fe3ccbf838bc4b9426ec40de18580585e2a3bc10813ca5c4f0f26784b681357b34c87767983e580cd51a7614924de0506ff919e5220d94509794cd03bb6564b0bfa2646970667358221220fa24862f196b2eb835b3adb158b35d6040e48413f187b6394a1046c860f147b364736f6c6343000814003300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000011000000000000000000000000fc9df6a32bd69319990e5689cc732dd79f9b256600000000000000000000000000000000000000000000000000000000000008ca000000000000000000000000580f8554ff3fbf5db07c7015350f9f0ec8282b1400000000000000000000000000000000000000000000000000000000000001f400000000000000000000000092962d9ef012a90a6b628d5500d82558de5dd3b400000000000000000000000000000000000000000000000000000000000001f400000000000000000000000065b25a3f882e77a72f24d94b549a79b8dd04d37900000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000d71c6b84e52eaa3a2637e298c4c84dcb7f87299200000000000000000000000000000000000000000000000000000000000000fa000000000000000000000000a813e1153c52a03324ca21ba74db741f6862132e00000000000000000000000000000000000000000000000000000000000000fa000000000000000000000000898eaf77048dc8ba156c846e967075def4120a5a00000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000057930254185719fdca8fc4f59b3034ebcb6726a300000000000000000000000000000000000000000000000000000000000000fa0000000000000000000000008fe2c33e3bfb491d5816ee06f8dcdd81e6b79999000000000000000000000000000000000000000000000000000000000000007d000000000000000000000000baebc436547c1d11a5c6d96a92e04cb1de35b9a2000000000000000000000000000000000000000000000000000000000000007d00000000000000000000000062f7c2259339df3e09742dec0c2c1f55cfe14aaa0000000000000000000000000000000000000000000000000000000000000992000000000000000000000000009b5404312e4bb3301a08071d1dbd576ccbb6310000000000000000000000000000000000000000000000000000000000000992000000000000000000000000bf707c2b39b3078e9f1c9590a2e5ad848c7cd9e3000000000000000000000000000000000000000000000000000000000000001400000000000000000000000065fa6950c0c5cb2a68e35849b8a66442b39283bc0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000ec50a03232854c59b39b5e5d56ba5e3132f15b5300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000c5402bf143d20580a1bc68959d0b4271d95dfe70000000000000000000000000000000000000000000000000000000000000014000000000000000000000000cff8fefc4ad3f168d95e56405253c686d9161c6e0000000000000000000000000000000000000000000000000000000000000014

Deployed Bytecode

0x608060408181526004918236101561003a575b50505036156100325761002361151b565b61002b61149c565b6001600055005b61002361151b565b600090813560e01c9081630134aeba146112d657508063078ba1d41461123f5780631f69692414611139578063432994bf146110f05780634c6f7c77146110b85780634e9beead146110b85780636a2239e114610e9e5780636bd3470e14610d37578063726f16d814610e505780639275184414610e185780639c22b9a614610df95780639c4df63614610d5b5780639cc72f7f14610d3c578063a0a9a85d14610d37578063a28ece7214610c04578063aecf9f8f14610ab1578063b8b9b54914610b5c578063c8b664c914610b3e578063c8e706e214610afa578063cdca2bd314610ab1578063d47f6877146109c9578063db16c12a146109ab578063dcbe32e6146106a0578063ee51273b1461067f578063f5f6d3af146102d9578063fa66358a146102485763fde728a5036100125734610245578160031936011261024557610184611328565b9260243567ffffffffffffffff8111610241576101a490369083016112f2565b946001600160a01b0390811692831561023357509490839584925b8084106101eb57848652600560209081528787205488518a815291820181905289146040820152606090f35b9091929661022561022b918461020a6102058c878a612119565b612129565b16885260206003815289892090888a52528888205490611479565b97611583565b9291906101bf565b8551630f58058360e11b8152fd5b8280fd5b80fd5b5082903461024557602036600319011261024557508035906001548210156102a0575061027761027d91611429565b506120e1565b805160209182015192516001600160a01b03909116815290810191909152604090f35b606490602084519162461bcd60e51b83528201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152fd5b50919034610241576020908160031936011261067b576102f7611328565b9161030061151b565b6001600160a01b037f0000000000000000000000006bd8ab2b292183a58a0c3482db5459cd65ee25c28181169591338790036106685785169485156106585784516370a0823160e01b8082523085830152919085816024818b5afa90811561064e578a9161061d575b50878a5260058652868a2054908181111561060d57906103889161153e565b938651838152308282015286816024818c5afa908115610603578b916105d2575b50875163a9059cbb60e01b8882019081526001600160a01b0387166024830152604482018890528c918291906103ec81606481015b03601f19810183528261154b565b5190828d6201d4c0f1936103fe6115a5565b8561059f575b508851908152308382015287816024818d5afa908115610595578c91610564575b508082111561055b576104379161153e565b935b84156104f257508484116104ba5750508290867fe501bb37b6bef3426625fab8c3a24d8b13c03875431d7da0ac09609ce80d1f4c868851868152a2159182156104af575b5050610490575b50505050506001815580f35b60008051602061213e8339815191529251908152a33880808080610484565b14159050813861047d565b8651633624588160e21b81526001600160a01b03909216908201908152602081018590526040810184905281906060010390fd5b0390fd5b8590888b8b8a9760001461054b5760008051602061213e8339815191526104ee9697988451878152a35163c43b2e7760e01b81526001600160a01b03958616948101948552941660208401526040830152829160600190565b825163012a6c6b60e51b81528690fd5b50508993610439565b90508781813d831161058e575b61057b818361154b565b8101031261058a575138610425565b8b80fd5b503d610571565b89513d8e823e3d90fd5b8091955051908882159283156105ba575b5050509338610404565b6105ca935082018101910161182c565b3888816105b0565b90508681813d83116105fc575b6105e9818361154b565b810103126105f85751386103a9565b8a80fd5b503d6105df565b88513d8d823e3d90fd5b875163117ddeb560e11b81528690fd5b90508581813d8311610647575b610634818361154b565b81010312610643575138610369565b8980fd5b503d61062a565b87513d8c823e3d90fd5b8451630f58058360e11b81528390fd5b845160016210ee1d60e01b031981528390fd5b8380fd5b50903461069c578160031936011261069c576020905161c3508152f35b5080fd5b509134610241576020918260031936011261067b576106bd611328565b926106c661151b565b6001600160a01b03841692831561099d573386526003825282862084875282528286205494851561098e5783516370a0823160e01b8082523084830152919084816024818a5afa908115610984578991610953575b50855163a9059cbb60e01b868201908152336024830152604482018a90528a9182919061074b81606481016103de565b5190828b6201d4c0f19261075d6115a5565b84610920575b508651908152308582015285816024818b5afa90811561064e578a916108f3575b50808211156108ea576107969161153e565b925b831561087f5787841161084b57505085906107b3838361153e565b33895260038552858920878a52855285892055600584528488206107d884825461153e565b90558451838152867f8210728e7c071f615b840ee026032693858fbcd5e5359e67e438c890f59e5620863393a315918215610840575b5050610820575b505050506001815580f35b60008051602061213e83398151915291519384523393a338808080610815565b14159050843861080e565b8551633624588160e21b81526001600160a01b03909216908201908152602081018890526040810184905281906060010390fd5b868289888887156108da576104ee939460008051602061213e8339815191528351928584523393a35163c43b2e7760e01b81526001600160a01b03909316938301938452336020850152604084015290918291606090910190565b815163012a6c6b60e51b81528690fd5b50508792610798565b90508581813d8311610919575b61090a818361154b565b81010312610643575138610784565b503d610900565b80919450519086821592831561093b575b5050509238610763565b61094b935082018101910161182c565b388681610931565b90508481813d831161097d575b61096a818361154b565b8101031261097957513861071b565b8880fd5b503d610960565b86513d8b823e3d90fd5b5082516348d555c760e01b8152fd5b8251630f58058360e11b8152fd5b50903461069c578160031936011261069c57602090516201d4c08152f35b509190346102415782600319360112610241576109e461151b565b7f0000000000000000000000006bd8ab2b292183a58a0c3482db5459cd65ee25c2916001600160a01b0383163303610aa05747610a25600654835490611479565b9081811115610a90578580610a3c8194829461153e565b809761c350f1610a4a6115a5565b5015610a8257507f19b11090832956cdfe240feac6797d3886fbd25a8263687a67dff619e4a809989160209151908152a16001815580f35b90516338e81ea760e21b8152fd5b83516326c6886560e21b81528390fd5b905160016210ee1d60e01b03198152fd5b50903461069c578060031936011261069c5780602092610acf611328565b610ad761133e565b6001600160a01b0391821683526003865283832091168252845220549051908152f35b50903461069c578160031936011261069c57517f0000000000000000000000006bd8ab2b292183a58a0c3482db5459cd65ee25c26001600160a01b03168152602090f35b50913461024157826003193601126102415760209250549051908152f35b50919034610241578260031936011261024157610b7761151b565b600654918215610bcb575081602091610bb07f01d5a1e370499ab5939b7a1e819bccfcfd648d33bbdcef2c8b035b211af2c2f1946115e5565b610bbc8260065461153e565b60065551908152a16001815580f35b6020606492519162461bcd60e51b835282015260146024820152734e6f2045544820746f206469737472696275746560601b6044820152fd5b50823461069c576020908160031936011261024157610c21611328565b90610c2a61151b565b6001600160a01b0382168015610d285785516370a0823160e01b81523083820152908482602481845afa918215610d1e578692610ceb575b50855260058452858520549081811115610cdb5790610c809161153e565b928315610c995784610c928585611844565b6001815580f35b855162461bcd60e51b815291820152601760248201527f4e6f20746f6b656e7320746f2064697374726962757465000000000000000000604482015260649150fd5b86516348d555c760e01b81528390fd5b9091508481813d8311610d17575b610d03818361154b565b81010312610d1357519087610c62565b8580fd5b503d610cf9565b87513d88823e3d90fd5b508451630f58058360e11b8152fd5b611354565b50903461069c578160031936011261069c576020906001549051908152f35b50919034610241578260031936011261024157610d7661151b565b338352600260205280832054918215610deb5733845260026020528382812055610da183825461153e565b81558380808086335af1610db36115a5565b5015610a825750519081527f94b2de810873337ed265c5f8cf98c9cffefa06b8607f9a2f1fbaebdfbcfbef1c60203392a26001815580f35b9051630a73f65f60e21b8152fd5b50903461069c578160031936011261069c576020906006549051908152f35b50903461069c57602036600319011261069c5760209181906001600160a01b03610e40611328565b1681526005845220549051908152f35b50823461069c57602036600319011261069c5735906001548210156102455750610e7990611429565b50805460019091015491516001600160a01b0390911681526020810191909152604090f35b50823461069c578260031936011261069c57610eb8611328565b602491823592610ec661151b565b6001600160a01b03831680156110a85784156110665786516370a0823160e01b808252308583015260209687838681875afa92831561105c5788918a918295611028575b508b516323b872dd60e01b84820190815233898301908152306020820152604081019390935291610f3f9082906060016103de565b519082875af115610fff5787513d61101f5750823b155b611009578690848a5180958193825230898301525afa8015610fff578790610fca575b610f83925061153e565b938415610f955785610c928686611844565b865162461bcd60e51b81529283015260129082015271139bc81d1bdad95b9cc81c9958d95a5d995960721b6044820152606490fd5b50908581813d8311610ff8575b610fe1818361154b565b81010312610ff45790610f839151610f79565b8680fd5b503d610fd7565b88513d89823e3d90fd5b8851635274afe760e01b81528086018490528490fd5b60011415610f56565b92839195508092503d8311611055575b611042818361154b565b810103126109795788889151938c610f0a565b503d611038565b8a513d8b823e3d90fd5b865162461bcd60e51b8152602081850152601d818401527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606490fd5b8651630f58058360e11b81528390fd5b50903461069c57602036600319011261069c5760209181906001600160a01b036110e0611328565b1681526002845220549051908152f35b509134610241578260031936011261024157916020926111164791600654905490611479565b908181111561113157611129925061153e565b905b51908152f35b50509061112b565b5082903461024557806003193601126102455760019081549267ffffffffffffffff841161122c575083929193519360209461117a868560051b018261154b565b83815281835285810193837fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6865b8383106112015750505050845195869581870192828852518093528087019594905b8382106111d75787870388f35b855180516001600160a01b03168852830151878401528897509586019594820194908401906111ca565b9460028a82999a9b97611216859a989a6120e1565b81520192019201919098979694989593956111a8565b634e487b7160e01b825260419052602490fd5b509134610241576020928360031936011261024557813567ffffffffffffffff811161069c5761127290369084016112f2565b9091809581935b83851061129b5785548751898152602081018290529089146040820152606090f35b90919293966102256112cd9160018060a01b036112bc6102058c8a88612119565b168652600285528886205490611479565b93929190611279565b90503461069c578160031936011261069c576020906006548152f35b9181601f840112156113235782359167ffffffffffffffff8311611323576020808501948460051b01011161132357565b600080fd5b600435906001600160a01b038216820361132357565b602435906001600160a01b038216820361132357565b3461132357602080600319360112611323576001600160a01b03611376611328565b168015611417576040516370a0823160e01b8152306004820152908282602481845afa91821561140b576000926113dc575b50600052600582526040600020546000918181116000146113d5576113cd925061153e565b604051908152f35b50506113cd565b90918382813d8311611404575b6113f3818361154b565b8101031261024557505190386113a8565b503d6113e9565b6040513d6000823e3d90fd5b604051630f58058360e11b8152600490fd5b60015481101561146357600160005260011b7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60190600090565b634e487b7160e01b600052603260045260246000fd5b9190820180921161148657565b634e487b7160e01b600052601160045260246000fd5b60075460ff16156114e4576114b334600654611479565b6006556040513481527fd206448f7b56e8ac6ea4c25d631698548c420690635c4f1ec3ea85f768cea1cf60203392a2565b6040513481527f6ef95f06320e7a25a04a175ca677b7052bdd97131872c2192525a629f51be77060203392a2611519346115e5565b565b60026000541461152c576002600055565b604051633ee5aeb560e01b8152600490fd5b9190820391821161148657565b90601f8019910116810190811067ffffffffffffffff82111761156d57604052565b634e487b7160e01b600052604160045260246000fd5b60001981146114865760010190565b8181029291811591840414171561148657565b3d156115e0573d9067ffffffffffffffff821161156d57604051916115d4601f8201601f19166020018461154b565b82523d6000602084013e565b606090565b801561182957600160ff199181836007541617600755809180549160001983019283116114865760005b83811061170a575050508161162a575b505060075416600755565b61163381611429565b509060008080808660018060a01b038097541661c350f16116526115a5565b5015611698577f3202aa65eac199b43dfb2dbcaaea2d51df13baa8a0282f3d13fb2381a4187fb591611685602092611429565b50541692604051908152a25b388061161f565b816116fa827f1c43b9761b3fba5321ca8212bfc231945f668ccc0c446f333999eea9ce8fda81946116ca602095611429565b5054166000526002845260406000206116e4878254611479565b90556116f286600454611479565b600455611429565b50541692604051908152a2611691565b6127106117238461171a84611429565b50015484611592565b0480611739575b5061173490611583565b61160f565b9490611748866117349361153e565b9561175282611429565b5060008080808560018060a01b038096541661c350f16117706115a5565b50156117b55760207f3202aa65eac199b43dfb2dbcaaea2d51df13baa8a0282f3d13fb2381a4187fb5916117a385611429565b50541692604051908152a25b9061172a565b907f1c43b9761b3fba5321ca8212bfc231945f668ccc0c446f333999eea9ce8fda8190826117e285611429565b5054166000526020906002825260409384600020611801838254611479565b90556004611810838254611479565b905561181b86611429565b5054169351908152a26117af565b50565b90816020910312611323575180151581036113235790565b9080600090600180549160001983019283116120cd57835b838110611cef575050508261196f575b50506040516370a0823160e01b81523060048201526001600160a01b0390921691602091508181602481865afa90811561140b57600091611942575b5080611913575b826000526005825260406000205460009181811160001461190b576118d4925061153e565b905b816118e057505050565b7f69daea1f10f0159fc50d869130336ad6f2803f97957a5113415a3c98338d0c0591604051908152a2565b5050906118d6565b827f2e7c052eb4d23d62b74d28ad223e3e160e10279f69c7c38910c945ee1797a2bf83604051848152a26118af565b908282813d8311611968575b611958818361154b565b81010312610245575051386118a8565b503d61194e565b604080516370a0823160e01b80825230600483015291946001600160a01b038781169560209492939192909185816024818b5afa908115611ce457600091611cb7575b50600080856119c08a611429565b50548c5163a9059cbb60e01b8b8201908152929091166001600160a01b03166024820152604481018990526119f881606481016103de565b5190828c6201d4c0f191611a0a6115a5565b83611c84575b50895190815230600482015286816024818c5afa908115611c7957600091611c4c575b5060009181811115611c4457611a49925061153e565b915b8215611bb657848311611b885790611a64838693611479565b5083611a6f88611429565b505416887fbc4928bea7c4dad9c3e119c0eeb09bc569f266709f76666d74f34ef1441aefa6888c51878152a3818310611af9575b15918215611aee575b5050611ac2575b5050505050505b38808061186c565b611ada60008051602061213e83398151915294611429565b5054169451908152a3388080808080611ab3565b141590508238611aac565b611b03838361153e565b84611b0d89611429565b5054166000526003875289600020896000528752611b308a600020918254611479565b9055611b3c838361153e565b8860005260058752611b538a600020918254611479565b905583611b5f88611429565b5054168860008051602061215e83398151915288611b7d878761153e565b8d51908152a3611aa3565b8851633624588160e21b81526001600160a01b038b1660048201526024810186905260448101849052606490fd5b50159050611be457611bd660008051602061213e83398151915294611429565b5054169451908152a3611aba565b611bd68482611c0160008051602061215e83398151915297611429565b505416600052600385528760002087600052855287600020611c24858254611479565b9055866000526005855287600020611c3d858254611479565b9055611429565b505091611a4b565b908782813d8311611c72575b611c62818361154b565b8101031261024557505138611a33565b503d611c58565b8a513d6000823e3d90fd5b809193505190878215928315611c9f575b5050509138611a10565b611caf935082018101910161182c565b388781611c95565b908682813d8311611cdd575b611ccd818361154b565b81010312610245575051386119b2565b503d611cc3565b89513d6000823e3d90fd5b612710611d028461171a84999899611429565b049485156120c15785611d149161153e565b9560409081516370a0823160e01b90818152600498308a83015260018060a01b0392838d1694602093602492858285818b5afa918215611ce4578e918986888d8f8d908d9760009a612067575b5092611dae60009694936103de88979594611d7c8996611429565b50541691519384928c84019763a9059cbb60e01b8952840160209093929193604081019460018060a01b031681520152565b51926201d4c0f195611dbe6115a5565b87612034575b508b5193849283523090830152818b5afa908115611ce457600091612007575b5060009181811115611fff57611dfa925061153e565b9b5b8c15611f6557838d11611f2f575090611e1e8c611e6e99989796959493611479565b9b84611e2989611429565b505416867fbc4928bea7c4dad9c3e119c0eeb09bc569f266709f76666d74f34ef1441aefa6868a51858152a3828110611e9f575b5015611e73575b5050505050611583565b61185c565b60008051602061213e83398151915292611e8c87611429565b5054169451908152a33880808080611e64565b611ea9818461153e565b85611eb38a611429565b5054166000526003855287600020876000528552611ed688600020918254611479565b9055611ee2818461153e565b8660005260058552611ef988600020918254611479565b90558560008051602061215e83398151915285611f2388611f198d611429565b505416948761153e565b8a51908152a338611e5d565b8e906104ee8e868b51948594633624588160e21b86528501604091949392606082019560018060a01b0316825260208201520152565b509a50611e6e9695949392919015611f9e5760008051602061213e83398151915292611f9087611429565b5054169451908152a3611583565b8260008051602061215e83398151915293611fb888611429565b505416600052600383528560002085600052835285600020611fdb838254611479565b9055846000526005835285600020611ff4838254611479565b9055611f9087611429565b50509b611dfc565b908682813d831161202d575b61201d818361154b565b8101031261024557505138611de4565b503d612013565b80919750519083821592831561204f575b5050509538611dc4565b61205f935082018101910161182c565b388381612045565b9850505050505050929082813d83116120ba575b612085818361154b565b810103126102455750858a928f9260008b88828f611dae8f916103de8f93611d7c869a519e95989a5050945050939550611d61565b503d61207b565b959450611e6e90611583565b634e487b7160e01b84526011600452602484fd5b906040516040810181811067ffffffffffffffff82111761156d5760405282546001600160a01b031681526001909201546020830152565b91908110156114635760051b0190565b356001600160a01b0381168103611323579056fe3ccbf838bc4b9426ec40de18580585e2a3bc10813ca5c4f0f26784b681357b34c87767983e580cd51a7614924de0506ff919e5220d94509794cd03bb6564b0bfa2646970667358221220fa24862f196b2eb835b3adb158b35d6040e48413f187b6394a1046c860f147b364736f6c63430008140033

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.