ETH Price: $3,395.93 (-1.83%)
Gas: 6 Gwei

Contract

0x31B9b834C78415Df06Df0cA67B715484Bfc16a0F
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Exchange ETH189050132023-12-31 10:57:47201 days ago1704020267IN
0x31B9b834...4Bfc16a0F
0.03 ETH0.0005840512.1485065
Exchange ETH189050062023-12-31 10:56:23201 days ago1704020183IN
0x31B9b834...4Bfc16a0F
0.03 ETH0.0006049512.58333224
Exchange ETH189049952023-12-31 10:54:11201 days ago1704020051IN
0x31B9b834...4Bfc16a0F
0.06 ETH0.000597512.42826975
Exchange ETH189049802023-12-31 10:51:11201 days ago1704019871IN
0x31B9b834...4Bfc16a0F
0.03 ETH0.000631713.13961447
Exchange ETH188913062023-12-29 12:42:11202 days ago1703853731IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0008011216.66373649
Exchange APE188865752023-12-28 20:47:23203 days ago1703796443IN
0x31B9b834...4Bfc16a0F
0 ETH0.0017136123
Exchange WETH188849772023-12-28 15:23:59203 days ago1703777039IN
0x31B9b834...4Bfc16a0F
0 ETH0.002409843.27649121
Exchange ETH188845322023-12-28 13:54:23203 days ago1703771663IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0015921933.11834627
Exchange ETH188826892023-12-28 7:40:59204 days ago1703749259IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0012927726.8901379
Exchange ETH188790722023-12-27 19:28:35204 days ago1703705315IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.002082631.95348022
Exchange ETH188786222023-12-27 17:56:59204 days ago1703699819IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0023121835.4759429
Exchange WETH188744532023-12-27 3:53:59205 days ago1703649239IN
0x31B9b834...4Bfc16a0F
0 ETH0.0007319112.10104297
Exchange ETH188656552023-12-25 22:17:59206 days ago1703542679IN
0x31B9b834...4Bfc16a0F
0.09 ETH0.0009776214.99981442
Exchange ETH188503932023-12-23 18:47:35208 days ago1703357255IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0010523121.88866065
Exchange ETH188270712023-12-20 12:18:23211 days ago1703074703IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0039260560.23767579
Exchange ETH188162072023-12-18 23:40:47213 days ago1702942847IN
0x31B9b834...4Bfc16a0F
0.03 ETH0.0028650443.95861395
Exchange ETH188125502023-12-18 11:22:35214 days ago1702898555IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0018673238.84106809
Exchange ETH188124212023-12-18 10:56:23214 days ago1702896983IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0019970241.53895597
Exchange ETH188090622023-12-17 23:38:59214 days ago1702856339IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0029121644.68154429
Exchange ETH188065322023-12-17 15:07:35214 days ago1702825655IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0024794751.57414081
Exchange ETH187771472023-12-13 12:07:23218 days ago1702469243IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0017123635.61792709
Exchange ETH187656262023-12-11 21:25:11220 days ago1702329911IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.001930840.16141517
Exchange APE187646972023-12-11 18:18:11220 days ago1702318691IN
0x31B9b834...4Bfc16a0F
0 ETH0.0028702550
Exchange WETH187551322023-12-10 10:11:59222 days ago1702203119IN
0x31B9b834...4Bfc16a0F
0 ETH0.0013462224.17611371
Exchange ETH187550832023-12-10 10:02:11222 days ago1702202531IN
0x31B9b834...4Bfc16a0F
0.015 ETH0.0018505328.39296355
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
189050132023-12-31 10:57:47201 days ago1704020267
0x31B9b834...4Bfc16a0F
0.03 ETH
189050062023-12-31 10:56:23201 days ago1704020183
0x31B9b834...4Bfc16a0F
0.03 ETH
189049952023-12-31 10:54:11201 days ago1704020051
0x31B9b834...4Bfc16a0F
0.06 ETH
189049802023-12-31 10:51:11201 days ago1704019871
0x31B9b834...4Bfc16a0F
0.03 ETH
188913062023-12-29 12:42:11202 days ago1703853731
0x31B9b834...4Bfc16a0F
0.015 ETH
188845322023-12-28 13:54:23203 days ago1703771663
0x31B9b834...4Bfc16a0F
0.015 ETH
188826892023-12-28 7:40:59204 days ago1703749259
0x31B9b834...4Bfc16a0F
0.015 ETH
188790722023-12-27 19:28:35204 days ago1703705315
0x31B9b834...4Bfc16a0F
0.015 ETH
188786222023-12-27 17:56:59204 days ago1703699819
0x31B9b834...4Bfc16a0F
0.015 ETH
188656552023-12-25 22:17:59206 days ago1703542679
0x31B9b834...4Bfc16a0F
0.09 ETH
188503932023-12-23 18:47:35208 days ago1703357255
0x31B9b834...4Bfc16a0F
0.015 ETH
188270712023-12-20 12:18:23211 days ago1703074703
0x31B9b834...4Bfc16a0F
0.015 ETH
188162072023-12-18 23:40:47213 days ago1702942847
0x31B9b834...4Bfc16a0F
0.03 ETH
188125502023-12-18 11:22:35214 days ago1702898555
0x31B9b834...4Bfc16a0F
0.015 ETH
188124212023-12-18 10:56:23214 days ago1702896983
0x31B9b834...4Bfc16a0F
0.015 ETH
188090622023-12-17 23:38:59214 days ago1702856339
0x31B9b834...4Bfc16a0F
0.015 ETH
188065322023-12-17 15:07:35214 days ago1702825655
0x31B9b834...4Bfc16a0F
0.015 ETH
187771472023-12-13 12:07:23218 days ago1702469243
0x31B9b834...4Bfc16a0F
0.015 ETH
187656262023-12-11 21:25:11220 days ago1702329911
0x31B9b834...4Bfc16a0F
0.015 ETH
187550832023-12-10 10:02:11222 days ago1702202531
0x31B9b834...4Bfc16a0F
0.015 ETH
187152682023-12-04 20:04:47227 days ago1701720287
0x31B9b834...4Bfc16a0F
0.03 ETH
187152652023-12-04 20:04:11227 days ago1701720251
0x31B9b834...4Bfc16a0F
0.03 ETH
187071352023-12-03 16:44:59228 days ago1701621899
0x31B9b834...4Bfc16a0F
0.03 ETH
186803362023-11-29 22:46:11232 days ago1701297971
0x31B9b834...4Bfc16a0F
0.015 ETH
186802972023-11-29 22:38:23232 days ago1701297503
0x31B9b834...4Bfc16a0F
0.03 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TraitSwapping

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 11 : TraitSwapping.sol
// SPDX-License-Identifier: MIT
//
//              @@@@@@@@@@        @@@@@@@     @@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@
//            @@@@@@@@@@@@       @@@@@@@    .@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@
//          @@@@@@@@@@@@@@      @@@@@@@           @@@@@@@        @@@@@@     @@@@@@
//         @@@@@@@ @@@@@@@     @@@@@@@           @@@@@@@         @@@@@@@@@@@
//       @@@@@@@   @@@@@@@     @@@@@@            @@@@@@           @@@@@@@@@@@@@@
//      @@@@@@@@@@@@@@@@@@    @@@@@@@           @@@@@@@               #@@@@@@@@@@
//    @@@@@@@@@@@@@@@@@@@@   @@@@@@@           @@@@@@@        @@@@@@@     @@@@@@#
//   @@@@@@@@@@@@@@@@@@@@@   @@@@@@@@@@@@@@@@ @@@@@@@         @@@@@@@@@@@@@@@@@
// @@@@@@@          @@@@@@  @@@@@@@@@@@@@@@@ @@@@@@@            @@@@@@@@@@@@

pragma solidity ^0.8.21;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";

interface IRVM {
    function burn(address account, uint256 id, uint256 value) external;

    function isApprovedForAll(address account, address operator) external view returns (bool);
}

interface IALTS {
    function ownerOf(uint256 tokenId) external view returns (address);
}

contract TraitSwapping is Ownable, Pausable, ReentrancyGuard, IERC1155Receiver {
    using SafeERC20 for IERC20;
    IERC20 public immutable APE;
    IRVM public immutable RVM;
    IALTS public immutable ALTS;
    IERC20 public immutable WETH;

    enum Currency {
        ETH,
        WETH,
        APE,
        RVM
    }

    enum OrderStatus {
        UNSET,
        PENDING,
        ACCEPTED,
        CANCELED
    }

    struct Order {
        address buyer;
        uint96 amount;
        address seller;
        uint32 expiresAt;
        uint24 id;
        uint16 buyerAlt;
        uint16 sellerAlt;
        OrderStatus status;
    }

    struct Transfer {
        address buyer;
        uint16[3] buyerAlts;
        uint16[3] sellerAlts;
        address seller;
        uint72 amount;
        uint24 id;
    }

    struct Exchange {
        uint72 rateApe;
        uint56 rateEth;
        uint56 minFee;
        uint56 minOrder;
        uint8 rateRvm;
        uint8 fee;
    }

    Exchange public exchange;
    address payable public receiver;
    address public permittedOperator;
    bool public pointsTransfers = false;
    uint32 public expiryPeriod;
    uint24 public totalOrders = 0;
    uint24 public totalTransfers = 0;

    mapping(address => uint256) public points;
    mapping(uint56 => Order) public orders;
    mapping(uint96 => Transfer) private transfers;

    event PointsPurchase(
        address indexed user,
        Currency indexed currency,
        uint256 value,
        uint256 indexed points,
        uint256 currentPointsBalance
    );
    event TransferPoints(address indexed sender, address indexed receiver, uint256 amount);
    event TransferWETH(uint96 indexed id, address indexed buyer, address indexed seller, uint256 amount, uint256 fee);
    event OrderCreated(
        uint56 indexed orderId,
        address indexed buyer,
        address indexed seller,
        uint256 amount,
        uint32 expiresAt
    );
    event OrderFulfilled(uint56 indexed orderId);
    event OrderCanceled(uint56 indexed orderId, address indexed buyer, address indexed seller, uint256 amount);

    constructor(
        uint56 _rateEth,
        uint72 _rateApe,
        uint8 _rateRvm,
        uint56 _minFee,
        uint56 _minOrder,
        uint8 _fee,
        uint32 _expiryPeriod,
        address _ape,
        address _rvm,
        address _weth,
        address _alts,
        address _permittedOperator,
        address payable _receiver
    ) {
        exchange.rateEth = _rateEth;
        exchange.rateApe = _rateApe;
        exchange.rateRvm = _rateRvm;
        exchange.minFee = _minFee;
        exchange.minOrder = _minOrder;
        exchange.fee = _fee;
        expiryPeriod = _expiryPeriod;
        APE = IERC20(_ape);
        RVM = IRVM(_rvm);
        WETH = IERC20(_weth);
        ALTS = IALTS(_alts);
        permittedOperator = _permittedOperator;
        receiver = _receiver;
    }

    modifier onlyPermittedOperator() {
        require(msg.sender == permittedOperator || msg.sender == owner(), "Not a permitted operator");
        _;
    }

    /// @notice Exchanges ETH for swapping points.
    function exchangeETH() external payable nonReentrant whenNotPaused {
        require(msg.value > 0, "Amount cannot be 0");
        require(msg.value % exchange.rateEth == 0, "Invalid ETH amount");
        uint256 pointsToReceive = msg.value / exchange.rateEth;
        points[msg.sender] += pointsToReceive;
        (bool sent, ) = receiver.call{value: msg.value}("");
        require(sent, "Failed to send ETH");
        emit PointsPurchase(msg.sender, Currency.ETH, msg.value, pointsToReceive, points[msg.sender]);
    }

    /// @notice Exchanges WETH for swapping points.
    /// @param amount The amount of WETH to be exchanged.
    function exchangeWETH(uint256 amount) external nonReentrant whenNotPaused {
        require(amount > 0, "Amount cannot be 0");
        require(amount % exchange.rateEth == 0, "Invalid WETH amount");
        uint256 pointsToReceive = amount / exchange.rateEth;
        points[msg.sender] += pointsToReceive;
        WETH.safeTransferFrom(msg.sender, receiver, amount);
        emit PointsPurchase(msg.sender, Currency.WETH, amount, pointsToReceive, points[msg.sender]);
    }

    /// @notice Exchanges APE coin for swapping points.
    /// @param amount The amount of APE to be exchanged.
    function exchangeAPE(uint256 amount) external nonReentrant whenNotPaused {
        require(amount > 0, "Amount cannot be 0");
        require(amount % exchange.rateApe == 0, "Invalid APE amount");
        uint256 pointsToReceive = amount / exchange.rateApe;
        points[msg.sender] += pointsToReceive;
        APE.safeTransferFrom(msg.sender, receiver, amount);
        emit PointsPurchase(msg.sender, Currency.APE, amount, pointsToReceive, points[msg.sender]);
    }

    /// @notice Exchanges RVM coins for points.
    /// @param amount The amount of RVM coins to be exchanged.
    function exchangeRVM(uint256 amount) external nonReentrant whenNotPaused {
        require(amount > 0, "Amount cannot be 0");
        require(amount % exchange.rateRvm == 0, "Invalid RVM amount");
        uint256 pointsToReceive = amount / exchange.rateRvm;
        points[msg.sender] += pointsToReceive;
        RVM.burn(msg.sender, 0, amount);
        emit PointsPurchase(msg.sender, Currency.RVM, amount, pointsToReceive, points[msg.sender]);
    }

    /// @notice Enables a user to create a WETH transfer.
    /// @param transfer The details of the new WETH transfer.
    function executeWETHOrder(Transfer memory transfer) external nonReentrant whenNotPaused {
        require(transfer.buyer == msg.sender, "Buyer must create own order");
        require(transfer.amount >= exchange.minOrder, "Transfer amount is below minimum");
        require(validateAltsOwnership(transfer.buyerAlts, msg.sender), "Buyer: no valid ALT ID");
        require(validateAltsOwnership(transfer.sellerAlts, transfer.seller), "Seller: no valid ALT ID");

        unchecked {
            uint256 minFee = exchange.minFee;
            uint256 calculatedFee = (transfer.amount * exchange.fee) / 100;
            uint256 feeAmount = calculatedFee < minFee ? minFee : calculatedFee;

            totalTransfers++;
            transfer.id = totalTransfers;
            transfers[transfer.id] = transfer;

            address buyer = transfer.buyer;
            WETH.safeTransferFrom(buyer, receiver, feeAmount);
            WETH.safeTransferFrom(buyer, transfer.seller, transfer.amount);

            emit TransferWETH(transfer.id, transfer.buyer, transfer.seller, transfer.amount, feeAmount);
        }
    }

    /// @notice Enables a user to create a new WETH offer.
    /// @param order The details of the new WETH offer.
    function createOrder(Order memory order) external nonReentrant whenNotPaused {
        require(order.buyer == msg.sender, "Buyer must create their own order");
        require(order.buyerAlt >= 1 && order.buyerAlt <= 30000, "Invalid buyer ALT ID");
        require(order.sellerAlt >= 1 && order.sellerAlt <= 30000, "Invalid seller ALT ID");
        require(order.amount >= exchange.minOrder, "Order amount is below minimum");

        require(ALTS.ownerOf(order.buyerAlt) == msg.sender, "Buyer does not own the specified ALT");
        require(ALTS.ownerOf(order.sellerAlt) == order.seller, "Seller does not own the specified ALT");

        // No overflow in unchecked block as order.amount is uint96 and exchange.fee is max 100
        unchecked {
            uint256 minFee = exchange.minFee;
            uint256 calculatedFee = (order.amount * exchange.fee) / 100;
            uint256 feeAmount = calculatedFee < minFee ? minFee : calculatedFee;

            require(
                WETH.allowance(msg.sender, address(this)) >= order.amount + feeAmount,
                "Insufficient WETH allowance"
            );

            totalOrders++;
        }

        order.id = totalOrders;
        order.status = OrderStatus.PENDING;
        order.expiresAt = uint32(block.timestamp + expiryPeriod);
        orders[order.id] = order;

        emit OrderCreated(order.id, order.buyer, order.seller, order.amount, order.expiresAt);
    }

    /// @notice Enables a user to cancel a WETH offer.
    /// @param id The ID of the WETH offer to be canceled.
    function cancelOrder(uint56 id) external nonReentrant whenNotPaused {
        Order storage order = orders[id];
        OrderStatus status = order.status;

        require(status != OrderStatus.UNSET, "Order does not exist");
        require(status == OrderStatus.PENDING, "Order is not pending");

        address buyer = order.buyer;

        require(
            buyer == msg.sender || permittedOperator == msg.sender || owner() == msg.sender,
            "Not the buyer of this order"
        );

        order.status = OrderStatus.CANCELED;

        emit OrderCanceled(id, buyer, order.seller, order.amount);
    }

    /// @notice Fulfills a specific WETH offer.
    /// @param id The ID of the WETH offer to be fulfilled.
    function fulfillOrder(uint56 id) external onlyPermittedOperator {
        Order storage order = orders[id];
        require(order.status == OrderStatus.PENDING, "Order not eligible for fulfillment");

        if (block.timestamp > order.expiresAt) {
            revert("Expired");
        }

        unchecked {
            uint256 orderAmount = order.amount;
            uint256 feeAmount = (orderAmount * exchange.fee) / 100;

            if (feeAmount < exchange.minFee) {
                feeAmount = exchange.minFee;
            }
            // WETH calls in unchecked block scope vs separate declarations
            address buyer = order.buyer;
            WETH.safeTransferFrom(buyer, receiver, feeAmount);
            WETH.safeTransferFrom(buyer, order.seller, orderAmount);
        }

        order.status = OrderStatus.ACCEPTED;
        emit OrderFulfilled(id);
    }

    /// @notice Enables a user to send their points to another user.
    /// @param to The address to receive the points.
    /// @param amount The amount of points to send.
    function transferPoints(address to, uint256 amount) external nonReentrant whenNotPaused {
        require(pointsTransfers, "Transfers of points are disabled");
        require(to != address(0), "Cannot send to zero address");
        require(points[msg.sender] >= amount, "Insufficient points balance");

        points[msg.sender] -= amount;
        points[to] += amount;

        emit TransferPoints(msg.sender, to, amount);
    }

    /// @notice Overwrite the current points balance for the given users.
    /// @param users The list of user addresses.
    /// @param balances The corresponding list of point balances for each user.
    function setPoints(address[] calldata users, uint256[] calldata balances) external onlyPermittedOperator {
        require(users.length == balances.length, "Mismatched arrays");
        unchecked {
            for (uint256 i = 0; i < users.length; i++) {
                points[users[i]] = balances[i];
            }
        }
    }

    /// @notice Increments or decrements the current points balance for the given users by the given amount(s).
    /// @param users The list of user addresses whose points should be incremented or decremented.
    /// @param adjustments The corresponding list of point adjustments (positive for increments, negative for decrements) for each user.
    function adjustPoints(address[] calldata users, int256[] calldata adjustments) external onlyPermittedOperator {
        require(users.length == adjustments.length, "Mismatched arrays");
        unchecked {
            for (uint256 i = 0; i < users.length; i++) {
                if (adjustments[i] > 0) {
                    points[users[i]] += uint256(adjustments[i]);
                } else {
                    require(points[users[i]] >= uint256(-adjustments[i]), "Cannot decrease below zero");
                    points[users[i]] -= uint256(-adjustments[i]);
                }
            }
        }
    }

    /// @notice Sets the wallet to receive exchange payments.
    /// @param _receiver The new address of the receiver.
    function setReceiver(address payable _receiver) external onlyOwner {
        receiver = _receiver;
    }

    /// @notice Sets the period from order creation block timestamp after which orders should expire.
    /// @param period The new expiry period in seconds (e.g. 14 days is 1209600).
    function setExpiryPeriod(uint32 period) external onlyOwner {
        expiryPeriod = period;
    }

    /// @notice Sets WETH fee and exchange rates for the supported currencies and tokens.
    /// @param eth The exchange rate for ETH.
    /// @param ape The exchange rate for APE coin.
    /// @param rvm The exchange rate for RVM coin.
    /// @param fee The fee applied to WETH offers.
    function setExchange(
        uint56 eth,
        uint72 ape,
        uint8 rvm,
        uint8 fee,
        uint56 minFee,
        uint56 minOrder
    ) external onlyOwner {
        exchange.rateApe = ape;
        exchange.rateEth = eth;
        exchange.minFee = fee;
        exchange.minOrder = minOrder;
        exchange.rateRvm = rvm;
        exchange.fee = fee;
    }

    /// @notice Sets the permitted operator address.
    /// @param _operator The address of the operator.
    function setPermittedOperator(address _operator) external onlyOwner {
        require(_operator != address(0), "Operator address cannot be null");
        permittedOperator = _operator;
    }

    /// @notice Removes permissions from the permitted operator.
    function removePermittedOperator() external onlyOwner {
        permittedOperator = address(0);
    }

    /// @notice Fetches allowances for the user for all supported tokens.
    /// @param user The address of the user.
    function getAllowances(address user) external view returns (uint256[] memory) {
        uint256[] memory allowances = new uint256[](3);
        allowances[0] = WETH.allowance(user, address(this));
        allowances[1] = APE.allowance(user, address(this));
        allowances[2] = RVM.isApprovedForAll(user, address(this)) ? 1 : 0;
        return allowances;
    }

    /// @notice Fetches orders including a specific wallet address between the given range.
    /// @param user The address of the user.
    /// @param start The starting ID of the order range.
    /// @param end The ending ID of the order range.
    /// @param isSeller Whether to fetch orders where the user is the buyer (WETH sender) or the seller (WETH receiver).
    function getOrdersByUser(
        address user,
        uint56 start,
        uint56 end,
        bool isSeller
    ) external view returns (uint56[] memory) {
        require(start <= end, "Invalid range");

        uint56[] memory orderRange = new uint56[](end - start + 1);
        uint256 count = 0;

        unchecked {
            for (uint56 i = start; i <= end; i++) {
                bool isUserOrder = (isSeller && orders[i].seller == user) || (!isSeller && orders[i].buyer == user);
                if (isUserOrder && orders[i].status != OrderStatus.UNSET) {
                    orderRange[count++] = i;
                }
            }
        }

        uint56[] memory result = new uint56[](count);
        unchecked {
            for (uint256 j = 0; j < count; j++) {
                result[j] = orderRange[j];
            }
        }
        return result;
    }

    /// @notice Gets informatiom about a WETH transfer
    /// @param transferId The ID of the transfer to get data for
    /// @dev Alternative to public transfers mapping to facilitate uint16[3] display
    function getTransfer(
        uint96 transferId
    ) public view returns (address, uint16[3] memory, uint16[3] memory, address, uint96, uint256) {
        Transfer storage t = transfers[transferId];
        return (t.buyer, t.buyerAlts, t.sellerAlts, t.seller, t.id, t.amount);
    }

    /// @notice Drains any Ether from the contract to the owner.
    /// @dev This is an emergency function for funds release.
    function drainETH() external onlyOwner {
        owner().call{value: address(this).balance}("");
    }

    /// @notice Drains any WETH from the contract to the owner.
    /// @dev This is an emergency function for funds release.
    function drainWETH() external onlyOwner {
        WETH.transfer(owner(), WETH.balanceOf(address(this)));
    }

    /// @notice Drains any APE tokens from the contract to the owner.
    /// @dev This is an emergency function for funds release.
    function drainAPE() external onlyOwner {
        APE.transfer(owner(), APE.balanceOf(address(this)));
    }

    /// @notice Enables peer-to-peer points transfer.
    function enableTransfers() external onlyOwner {
        pointsTransfers = true;
    }

    /// @notice Disables peer-to-peer points transfer.
    function disableTransfers() external onlyOwner {
        pointsTransfers = false;
    }

    /// @notice Pauses exchanges and points issuance.
    function pause() external onlyPermittedOperator {
        _pause();
    }

    /// @notice Unpauses exchanges and points issuance.
    function unpause() external onlyPermittedOperator {
        _unpause();
    }

    /// @dev Issues swapping points for RVM coins send to the contract.
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external override returns (bytes4) {
        require(address(RVM) == msg.sender, "Only RVM tokens accepted");
        require(id == 0, "Only RVM tokenId 0 accepted");

        uint256 pointsToReceive = value / exchange.rateRvm;
        points[from] += pointsToReceive;

        emit PointsPurchase(from, Currency.RVM, value, pointsToReceive, points[from]);

        RVM.burn(address(this), id, value);

        return this.onERC1155Received.selector;
    }

    /// @dev Declines batch transfers of ERC1155 tokens to the contract.
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external override returns (bytes4) {
        revert("Not supported");
    }

    /// @dev Supports IERC1155Receiver
    function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
        return interfaceId == type(IERC1155Receiver).interfaceId;
    }

    /// @notice Check a wallet owns the given ALTs
    /// @param tokenIds The ALT tokenIds to check
    /// @param owner The expected owner wallet address
    function validateAltsOwnership(uint16[3] memory tokenIds, address owner) internal view returns (bool) {
        bool validAlt = false;
        for (uint i = 0; i < 3; i++) {
            if (tokenIds[i] != 0) {
                validAlt = true;
                require(ALTS.ownerOf(tokenIds[i]) == owner, "ALT ownership mismatch");
            }
        }
        return validAlt;
    }
}

File 2 of 11 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

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

File 3 of 11 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 4 of 11 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @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 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;

    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
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // 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;
    }
}

File 5 of 11 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 6 of 11 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 7 of 11 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount) external returns (bool);
}

File 8 of 11 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 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 {
    using Address for address;

    /**
     * @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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @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.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

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

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @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).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @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 silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

File 9 of 11 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 10 of 11 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

File 11 of 11 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * 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[EIP 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);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint56","name":"_rateEth","type":"uint56"},{"internalType":"uint72","name":"_rateApe","type":"uint72"},{"internalType":"uint8","name":"_rateRvm","type":"uint8"},{"internalType":"uint56","name":"_minFee","type":"uint56"},{"internalType":"uint56","name":"_minOrder","type":"uint56"},{"internalType":"uint8","name":"_fee","type":"uint8"},{"internalType":"uint32","name":"_expiryPeriod","type":"uint32"},{"internalType":"address","name":"_ape","type":"address"},{"internalType":"address","name":"_rvm","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_alts","type":"address"},{"internalType":"address","name":"_permittedOperator","type":"address"},{"internalType":"address payable","name":"_receiver","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint56","name":"orderId","type":"uint56"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"OrderCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint56","name":"orderId","type":"uint56"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"expiresAt","type":"uint32"}],"name":"OrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint56","name":"orderId","type":"uint56"}],"name":"OrderFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"enum TraitSwapping.Currency","name":"currency","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"points","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentPointsBalance","type":"uint256"}],"name":"PointsPurchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferPoints","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint96","name":"id","type":"uint96"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"TransferWETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"ALTS","outputs":[{"internalType":"contract IALTS","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"APE","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RVM","outputs":[{"internalType":"contract IRVM","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"int256[]","name":"adjustments","type":"int256[]"}],"name":"adjustPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint56","name":"id","type":"uint56"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"buyer","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint32","name":"expiresAt","type":"uint32"},{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"uint16","name":"buyerAlt","type":"uint16"},{"internalType":"uint16","name":"sellerAlt","type":"uint16"},{"internalType":"enum TraitSwapping.OrderStatus","name":"status","type":"uint8"}],"internalType":"struct TraitSwapping.Order","name":"order","type":"tuple"}],"name":"createOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableTransfers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"drainAPE","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"drainETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"drainWETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableTransfers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchange","outputs":[{"internalType":"uint72","name":"rateApe","type":"uint72"},{"internalType":"uint56","name":"rateEth","type":"uint56"},{"internalType":"uint56","name":"minFee","type":"uint56"},{"internalType":"uint56","name":"minOrder","type":"uint56"},{"internalType":"uint8","name":"rateRvm","type":"uint8"},{"internalType":"uint8","name":"fee","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"exchangeAPE","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"exchangeRVM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"exchangeWETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"buyer","type":"address"},{"internalType":"uint16[3]","name":"buyerAlts","type":"uint16[3]"},{"internalType":"uint16[3]","name":"sellerAlts","type":"uint16[3]"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint72","name":"amount","type":"uint72"},{"internalType":"uint24","name":"id","type":"uint24"}],"internalType":"struct TraitSwapping.Transfer","name":"transfer","type":"tuple"}],"name":"executeWETHOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"expiryPeriod","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint56","name":"id","type":"uint56"}],"name":"fulfillOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getAllowances","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint56","name":"start","type":"uint56"},{"internalType":"uint56","name":"end","type":"uint56"},{"internalType":"bool","name":"isSeller","type":"bool"}],"name":"getOrdersByUser","outputs":[{"internalType":"uint56[]","name":"","type":"uint56[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint96","name":"transferId","type":"uint96"}],"name":"getTransfer","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint16[3]","name":"","type":"uint16[3]"},{"internalType":"uint16[3]","name":"","type":"uint16[3]"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint96","name":"","type":"uint96"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint56","name":"","type":"uint56"}],"name":"orders","outputs":[{"internalType":"address","name":"buyer","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint32","name":"expiresAt","type":"uint32"},{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"uint16","name":"buyerAlt","type":"uint16"},{"internalType":"uint16","name":"sellerAlt","type":"uint16"},{"internalType":"enum TraitSwapping.OrderStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permittedOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"points","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pointsTransfers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receiver","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"removePermittedOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint56","name":"eth","type":"uint56"},{"internalType":"uint72","name":"ape","type":"uint72"},{"internalType":"uint8","name":"rvm","type":"uint8"},{"internalType":"uint8","name":"fee","type":"uint8"},{"internalType":"uint56","name":"minFee","type":"uint56"},{"internalType":"uint56","name":"minOrder","type":"uint56"}],"name":"setExchange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"period","type":"uint32"}],"name":"setExpiryPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"}],"name":"setPermittedOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"name":"setPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_receiver","type":"address"}],"name":"setReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"totalOrders","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTransfers","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]

61010034620002f557601f6200380e38819003918201601f19168301916001600160401b03831184841017620002fa578084926101a094604052833981010312620002f5576200004f8162000310565b602082015191906001600160481b0383168303620002f557620000756040830162000325565b91620000846060820162000310565b90620000936080820162000310565b91620000a260a0830162000325565b9260c08301519463ffffffff86168603620002f557620000c560e0850162000334565b620000d4610100860162000334565b91620000e4610120870162000334565b93620000f4610140880162000334565b95610180620001076101608a0162000334565b9801519a6001600160a01b038c168c03620002f557600080546040519e9133906001600160a01b038316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36001600160a81b0319163360ff60a01b191617600055600180556004805460b89590951b66ffffffffffffff60b81b16608094851b66ffffffffffffff60801b1660f09490941b60ff60f01b166001600160481b0390931660489790971b6fffffffffffffff000000000000000000169690961791909117919091179390931760f89990991b7fff00000000000000000000000000000000000000000000000000000000000000908116999099176002556001600160a01b03938416905292821660a05292811660e05292831660c0529390931660a89490941b63ffffffff60a81b1693909317908316179055600380546001600160a01b031916929091169190911790556134c490816200034a8239608051818181611f4d01528181612768015281816129020152612ae7015260a051818181610f260152818161199b015281816129770152612b2c015260c0518181816103930152818161040201528181611a9901526133c8015260e0518181816104a801528181610b860152818161111d015281816117e7015281816120620152818161244b01526128a50152f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b519066ffffffffffffff82168203620002f557565b519060ff82168203620002f557565b51906001600160a01b0382168203620002f55756fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612c225750806303f153fd14612b815780630e36af7614612b5b57806310c85a3614612b165780631b5d145d14612ad15780631ce9029d146128315780631d8344091461280b5780632938a94f1461272d578063326f823f14612586578063358b81661461254d57806339f68f301461239f5780633a67a0f6146123765780633bf47720146123505780633d2cf8b2146123295780633e08409e146121755780633f4ba83a146120c1578063413fb05a14611fde5780634554f82a14611ec85780635c975abb14611ea35780635f81d91c14611dda5780636d8c6b4714611db1578063715018a614611d57578063718da7ee14611d1257806373f0f4cc14611cc25780638234228014611b775780638456cb5914611aef5780638da5cb5b14611ac85780638f0fd1ee14611a8357806394e989d11461192d5780639a80c4a1146118a2578063ab45ee7d14611816578063ad5c4648146117d1578063af35c6c7146117a2578063bc197c81146116f3578063c7042e52146116c7578063c969a67a1461146a578063cf171e1d146113a7578063cfa5f02a14611277578063d2f7265a14611212578063db928dd0146110e2578063e264172c146110aa578063f23a6e6114610ed2578063f2fde38b14610e0c578063f7260d3e14610de3578063fa9232701461092e5763fed2773c1461021b57600080fd5b3461092b5761010080600319360112610927576040519081018181106001600160401b0382111761091157604052610251612c90565b81526024356001600160601b03811681036106d55760208201526044356001600160a01b03811681036106d557604082015260643563ffffffff811681036106d557606082015262ffffff60843516608435036106d557608435608082015261ffff60a4351660a435036106d55760a43560a082015260c43561ffff811681036106d55760c082015260e435600481101561090d5760e08201526102f3612f59565b6102fb612f12565b80516001600160a01b031633036108be5761ffff60a082015116600181101590816108b1575b50156108755761ffff60c08201511660018110159081610868575b501561082b576001600160601b036020820151166002549066ffffffffffffff8260b81c16116107e65760a08201516040516331a9108f60e11b815261ffff90911660048201526020816024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9081156106e25784916107c7575b50336001600160a01b03909116036107765760c08201516040516331a9108f60e11b815261ffff90911660048201526020816024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9081156106e2578491610747575b5060408301516001600160a01b039081169116036106f4576001600160601b0360648166ffffffffffffff8460801c1693816020870151169060f81c021604168181106000146106ed57505b604051636eb1769f60e11b8152336004820152306024820152906020826044816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9182156106e25784926106a9575b506001600160601b0360208401511601116106645763ffffffff61053e8160045462ffffff60c81b600162ffffff8360c81c160160c81b169062ffffff60c81b1916178060045562ffffff8160c81c166080860152600160e086015260a81c1642612eb0565b16606082015262ffffff608082015116825260066020526040822060018060a01b038251166001600160601b0360a01b602084015160a01b161781556001808060a01b0360408401511663ffffffff60a01b606085015160a01b169062ffffff60c01b608086015160c01b1661ffff60d81b60a087015160d81b169061ffff60e81b60c088015160e81b169260e08801516105d881612c70565b6105e181612c70565b60ff60f81b9060f81b1694171717171791015562ffffff60808201511660018060a01b03825116907fbf40ec660247b3a483581bc742d72136a0f24b16506250925c2af28f821d8427604060018060a01b0381860151169463ffffffff60606001600160601b036020840151169201511682519182526020820152a46001805580f35b60405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e74205745544820616c6c6f77616e636500000000006044820152606490fd5b9091506020813d6020116106da575b816106c560209383612dbd565b810103126106d5575190386104d8565b600080fd5b3d91506106b8565b6040513d86823e3d90fd5b905061047e565b60405162461bcd60e51b815260206004820152602560248201527f53656c6c657220646f6573206e6f74206f776e20746865207370656369666965604482015264190810531560da1b6064820152608490fd5b610769915060203d60201161076f575b6107618183612dbd565b8101906131cf565b38610432565b503d610757565b60405162461bcd60e51b8152602060048201526024808201527f427579657220646f6573206e6f74206f776e20746865207370656369666965646044820152630810531560e21b6064820152608490fd5b6107e0915060203d60201161076f576107618183612dbd565b386103c3565b60405162461bcd60e51b815260206004820152601d60248201527f4f7264657220616d6f756e742069732062656c6f77206d696e696d756d0000006044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081cd95b1b195c88105315081251605a1b6044820152606490fd5b617530915011153861033c565b60405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a5908189d5e595c8810531508125160621b6044820152606490fd5b6175309150111538610321565b60405162461bcd60e51b815260206004820152602160248201527f4275796572206d75737420637265617465207468656972206f776e206f7264656044820152603960f91b6064820152608490fd5b8280fd5b634e487b7160e01b600052604160045260246000fd5b5080fd5b80fd5b503461092b5761014036600319011261092b5760405160c081018181106001600160401b0382111761091157604052610965612c90565b815236604312156106d55760405161097c81612da2565b806084913683116106d5576024905b838210610dcb57505060208301523660a312156106d5576040516109ae81612da2565b8060e4923684116106d557905b838210610db35750506040830152356001600160a01b03811681036106d5576060820152610104356001600160481b03811681036106d55760808201526101243562ffffff811681036106d55760a0820152610a15612f59565b610a1d612f12565b80516001600160a01b03163303610d6e576001600160481b036080820151166002549066ffffffffffffff90818360b81c1611610d2a57610a62336020850151613350565b15610cec57610a82604084015160018060a01b0360608601511690613350565b15610ca75760646001600160481b0380928460801c1693816080870151169060f81c02160416818110600014610ca057505b62ffffff6004548160e01b6001838360e01c160160e01b16908260e01b1916178060045560e01c168060a0840152835260076020526040832060018060a01b0383511690816001600160601b0360a01b82541617815560208401518590865b60038110610c6f575050600182015560408401518590865b60038110610c3e57505060028201556060840151608085015160a08681015191901b68ffffffffffffffffff60a01b166001600160a01b039283161760e89190911b6001600160e81b031916176003928301559054610bd8927f0000000000000000000000000000000000000000000000000000000000000000929091610bb6918691168385612faf565b60018060a01b03606086015116906001600160481b0360808701511692612faf565b62ffffff60a0830151167f514dd9353fa8ce618d8f1d8f37426441258fb5f94216c91926fbf561e09f0e6e604060018060a01b03855116936001600160481b03608060018060a01b03606089015116970151169082519182526020820152a46001805580f35b90916020610c6660019261ffff8651169085851b60031b9161ffff809116831b921b19161790565b93019101610b2b565b90916020610c9760019261ffff8651169085851b60031b9161ffff809116831b921b19161790565b93019101610b13565b9050610ab4565b60405162461bcd60e51b815260206004820152601760248201527f53656c6c65723a206e6f2076616c696420414c542049440000000000000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275109d5e595c8e881b9bc81d985b1a590810531508125160521b6044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f5472616e7366657220616d6f756e742069732062656c6f77206d696e696d756d6044820152fd5b60405162461bcd60e51b815260206004820152601b60248201527f4275796572206d75737420637265617465206f776e206f7264657200000000006044820152606490fd5b60208091610dc084612dde565b8152019101906109bb565b60208091610dd884612dde565b81520191019061098b565b503461092b578060031936011261092b576003546040516001600160a01b039091168152602090f35b503461092b57602036600319011261092b57610e26612c90565b610e2e612ded565b6001600160a01b03908116908115610e7e57600054826001600160601b0360a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b503461092b5760a036600319011261092b57610eec612c90565b50610ef5612ca6565b6044356064356084356001600160401b0381116110a657610f1a903690600401612d62565b50506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811693909290338503611061578161101c5760038694610f6d60ff60025460f01c1686612ea6565b9216808652600560205260408620610f86848254612eb0565b9055808652600560205260008051602061346f8339815191526040808820548151908882526020820152a4833b1561090d57606490836040519586948593637a94c56560e11b8552306004860152602485015260448401525af1801561101157610ffd575b60405163f23a6e6160e01b8152602090f35b6110078291612d8f565b61092b5780610feb565b6040513d84823e3d90fd5b60405162461bcd60e51b815260206004820152601b60248201527f4f6e6c792052564d20746f6b656e4964203020616363657074656400000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601860248201527f4f6e6c792052564d20746f6b656e7320616363657074656400000000000000006044820152606490fd5b8480fd5b503461092b578060031936011261092b576110c3612ded565b8080808060018060a01b0381541647905af1506110de612ed3565b5080f35b503461092b578060031936011261092b576110fb612ded565b80546040516370a0823160e01b81523060048201526020916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169291168382602481865afa90811561120757849286926111d4575b5060405163a9059cbb60e01b81526001600160a01b0390911660048201526024810191909152918290818681604481015b03925af180156111c95761119c578280f35b816111bb92903d106111c2575b6111b38183612dbd565b8101906130e3565b5038808280f35b503d6111a9565b6040513d85823e3d90fd5b8381949293503d8311611200575b6111ec8183612dbd565b810103126106d5579051839161118a611159565b503d6111e2565b6040513d87823e3d90fd5b503461092b578060031936011261092b5760c060025466ffffffffffffff90604051916001600160481b0382168352808260481c166020840152808260801c1660408401528160b81c16606083015260ff8160f01c16608083015260f81c60a0820152f35b508060031936011261092b5761128b612f59565b611293612f12565b61129e341515612e45565b66ffffffffffffff60025460481c166112b78134612e86565b61136d576112c59034612ea6565b3382526005602052604082206112dc828254612eb0565b9055818080803460018060a01b03600354165af16112f8612ed3565b501561133357338252600560205281604081205460405190348252602082015260008051602061346f83398151915260403392a46001805580f35b60405162461bcd60e51b815260206004820152601260248201527108cc2d2d8cac840e8de40e6cadcc8408aa8960731b6044820152606490fd5b60405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a590811551208185b5bdd5b9d60721b6044820152606490fd5b503461092b5760c036600319011261092b576113c1612c5a565b6024356001600160481b0381168091036106d5576044359060ff821682036106d55760643560ff811681036106d55766ffffffffffffff91608435838116036106d55760a43592831683036106d557611418612ded565b6fffffffffffffff00000000000000000060ff60f81b8360f81b169560481b16179060ff60801b9060801b16179066ffffffffffffff60b81b9060b81b16179060ff60f01b9060f01b16171760025580f35b503461092b57608036600319011261092b57611484612c90565b66ffffffffffffff91906024358381168082036106d557604435908582168092036106d55760643590811590811583036116c35783811161168e57830387811161167a5760019794939291908516880185811161166657856114ec91999799989698166132df565b978594875b61157c575b5050505050611504816132df565b94825b828110611551575050506040519260208085019181865286518093528160408701970193905b83821061153a5786880387f35b84518116885296820196938201939085019061152d565b938486611563839997859997996132cb565b511661156f82886132cb565b5201959395949294611507565b90888783828b9d9b989796959c9a9c16878111611657578689809482611631575b82156115fc575b826115d7575b50506115c3575b500116909192939497999896986114f1565b6115d0838b019a8d6132cb565b52386115b1565b6040919250838152600660205220015460f81c6115f381612c70565b1515838e6115aa565b9150878061160b575b916115a4565b5050819052600660205260408d20548d9084906001600160a01b03888116911614611605565b8390525050600660205260408d208301546001600160a01b03868116911614838e61159d565b505050509896989795976114f6565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b87526011600452602487fd5b60405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642072616e676560981b6044820152606490fd5b8680fd5b503461092b578060031936011261092b576116e0612ded565b600480546001600160a01b031916905580f35b503461092b5760a036600319011261092b5761170d612c90565b50611716612ca6565b506001600160401b0360443581811161090d57611737903690600401612ce8565b505060643581811161090d57611751903690600401612ce8565b50506084359081116109275761176b903690600401612d62565b505060405162461bcd60e51b815260206004820152600d60248201526c139bdd081cdd5c1c1bdc9d1959609a1b6044820152606490fd5b503461092b578060031936011261092b576117bb612ded565b6004805460ff60a01b1916600160a01b17905580f35b503461092b578060031936011261092b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461092b57602036600319011261092b57611830612c90565b611838612ded565b6001600160a01b0316801561185d576001600160601b0360a01b600454161760045580f35b60405162461bcd60e51b815260206004820152601f60248201527f4f70657261746f7220616464726573732063616e6e6f74206265206e756c6c006044820152606490fd5b503461092b576118b136612d18565b90929160018060a01b0391826004541633148015611921575b6118d3906131ee565b6118de81831461323a565b855b8281106118eb578680f35b806118f9600192848961327a565b358561190e61190984888b61327a565b6132a0565b16895260056020526040892055016118e0565b508554831633146118ca565b503461092b57602036600319011261092b5760043561194a612f59565b611952612f12565b61195d811515612e45565b60ff60025460f01c166119708183612e86565b611a495761197e9082612ea6565b90338352600560205260408320611996838254612eb0565b9055827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610927578190606460405180948193637a94c56560e11b83523360048401528160248401528760448401525af180156106e257611a35575b5060039033845260056020526040842054604051918252602082015260008051602061346f83398151915260403392a46001805580f35b92611a4260039294612d8f565b92906119fe565b60405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a590814959348185b5bdd5b9d60721b6044820152606490fd5b503461092b578060031936011261092b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461092b578060031936011261092b57546040516001600160a01b039091168152602090f35b503461092b578060031936011261092b57600454611b2290336001600160a01b0391821614908115611b6a575b506131ee565b611b2a612f12565b805460ff60a01b1916600160a01b1781556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602090a180f35b9050825416331438611b1c565b503461092b57611b8636612d18565b9160018060a09593951b0390816004541633148015611cb6575b611ba9906131ee565b611bb484821461323a565b855b818110611bc1578680f35b86611bcd82878961327a565b351315611c0b5780611be2600192878961327a565b3584611bf261190984878a61327a565b1689526005602052604089209081540190555b01611bb6565b82611c1a61190983858861327a565b16875260056020908082526040892054611c3584898b61327a565b358a0311611c7157908291611c4d600194898b61327a565b359186611c5e61190986898c61327a565b168b525260408920908154019055611c05565b60405162461bcd60e51b815260048101839052601a60248201527f43616e6e6f742064656372656173652062656c6f77207a65726f0000000000006044820152606490fd5b50855482163314611ba0565b503461092b57602036600319011261092b5760043563ffffffff8116810361092757611cec612ded565b6004805463ffffffff60a81b191660a89290921b63ffffffff60a81b1691909117905580f35b503461092b57602036600319011261092b576004356001600160a01b0381169081900361092757611d41612ded565b6001600160601b0360a01b600354161760035580f35b503461092b578060031936011261092b57611d70612ded565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461092b578060031936011261092b576004546040516001600160a01b039091168152602090f35b503461092b57602036600319011261092b576004356001600160601b038116809103610927576101409160409160608351611e1481612da2565b36903760608351611e2481612da2565b3690378152600760205220805460038201546001600160a01b03918216926001600160481b039290611e8690611e7c611e6b6002611e6460018501613311565b9301613311565b916040519788526020880190612cbc565b6080860190612cbc565b811660e08401528060e81c61010084015260a01c16610120820152f35b503461092b578060031936011261092b5760ff6020915460a01c166040519015158152f35b503461092b57602036600319011261092b57600435611ee5612f59565b611eed612f12565b611ef8811515612e45565b6001600160481b0360025416611f0e8183612e86565b611fa457611f1e60029183612ea6565b91338452600560205260408420611f36848254612eb0565b9055600354611f719082906001600160a01b0316337f0000000000000000000000000000000000000000000000000000000000000000612faf565b33845260056020526040842054604051918252602082015260008051602061346f83398151915260403392a46001805580f35b60405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a590810541148185b5bdd5b9d60721b6044820152606490fd5b503461092b57602036600319011261092b57600435611ffb612f59565b612003612f12565b61200e811515612e45565b66ffffffffffffff60025460481c166120278183612e86565b6120865761203760019183612ea6565b9133845260056020526040842061204f848254612eb0565b9055611f7181838060a01b0360035416337f0000000000000000000000000000000000000000000000000000000000000000612faf565b60405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a590815d1551208185b5bdd5b9d606a1b6044820152606490fd5b503461092b578060031936011261092b576004546120f390336001600160a01b0391821614908115611b6a57506131ee565b805460ff8160a01c16156121395760ff60a01b191681556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a180f35b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b503461092b576020806003193601126109275766ffffffffffffff612198612c5a565b6121a0612f59565b6121a8612f12565b169081835260068152604083209160018301918254938460f81c6121cb81612c70565b80156122ed57806121dd600192612c70565b036122b15754936001600160a01b038086169490919033861480156122a4575b8015612298575b15612253576001600160f81b038216600360f81b17905560405160a09690961c865216937f57ecb4ac08f8d8a76afc3b4d54c62085a1087af5c0e23c6e9c485565878cfd269190a46001805580f35b60405162461bcd60e51b815260048101859052601b60248201527f4e6f7420746865206275796572206f662074686973206f7264657200000000006044820152606490fd5b50338389541614612204565b50338360045416146121fd565b60405162461bcd60e51b81526004810183905260146024820152734f72646572206973206e6f742070656e64696e6760601b6044820152606490fd5b60405162461bcd60e51b815260048101849052601460248201527313dc99195c88191bd95cc81b9bdd08195e1a5cdd60621b6044820152606490fd5b503461092b578060031936011261092b57602063ffffffff60045460a81c16604051908152f35b503461092b578060031936011261092b57602062ffffff60045460e01c16604051908152f35b503461092b578060031936011261092b5761238f612ded565b6004805460ff60a01b1916905580f35b503461092b57602036600319011261092b576123b9612c5a565b6004546001600160a01b039190821633148015612541575b6123da906131ee565b66ffffffffffffff80911691828452600660205260408420906001820192835460018160f81c61240981612c70565b036124f15760a01c63ffffffff1642116124c2576124809254918260a01c926002549260648460f81c8602049360801c168084106124ba575b508116906124777f00000000000000000000000000000000000000000000000000000000000000009382600354168486612faf565b85541691612faf565b80546001600160f81b0316600160f91b1790557f0e69115e81cc62141207a4e223b36a112153d2040b6ee2c0cf3040d3cec0d64e8280a280f35b925081612442565b60405162461bcd60e51b8152602060048201526007602482015266115e1c1a5c995960ca1b6044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f4f72646572206e6f7420656c696769626c6520666f722066756c66696c6c6d656044820152611b9d60f21b6064820152608490fd5b508254821633146123d1565b503461092b57602036600319011261092b576020906040906001600160a01b03612575612c90565b168152600583522054604051908152f35b503461092b57604036600319011261092b576125a0612c90565b602435906125ac612f59565b6125b4612f12565b60ff60045460a01c16156126e9576001600160a01b03169081156126a45733835260056020528060408420541061265f5733835260056020526040832080549082820391821161264b5755818352600560205260408320612616828254612eb0565b90556040519081527f1939c1072ace2dbc5fa27e183bfe1df83062209fe28d9f01a477f503ee75a25060203392a36001805580f35b634e487b7160e01b85526011600452602485fd5b60405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e7420706f696e74732062616c616e636500000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527f43616e6e6f742073656e6420746f207a65726f206164647265737300000000006044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f5472616e7366657273206f6620706f696e7473206172652064697361626c65646044820152fd5b503461092b578060031936011261092b57612746612ded565b80546040516370a0823160e01b81523060048201526020916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169291168382602481865afa90811561120757849286926127d8575060405163a9059cbb60e01b81526001600160a01b03909116600482015260248101919091529182908186816044810161118a565b8381949293503d8311612804575b6127f08183612dbd565b810103126110a6579051839161118a611159565b503d6127e6565b503461092b578060031936011261092b57602062ffffff60045460c81c16604051908152f35b503461092b576020908160031936011261092b5761284d612c90565b91604051608081018181106001600160401b03821117612abd5760405260038152818101916060368437604051636eb1769f60e11b8082526001600160a01b03878116600484015230602484015290969183816044817f000000000000000000000000000000000000000000000000000000000000000086165afa908115612ab2578791612a85575b50845115612a335785526040519687526001600160a01b038216600488015230602488015282876044817f000000000000000000000000000000000000000000000000000000000000000085165afa968715612a7a578697612a47575b50835196600197881015612a33576040858101919091525163e985e9c560e01b81526001600160a01b039290921660048301523060248301528290829060449082907f0000000000000000000000000000000000000000000000000000000000000000165afa908115611207578591612a16575b5015612a1057845b8251600210156129fc5785919260ff86921660608201526040519380850191818652518092526040850195925b8281106129e95785870386f35b83518752958101959281019284016129dc565b634e487b7160e01b85526032600452602485fd5b836129af565b612a2d9150823d84116111c2576111b38183612dbd565b386129a7565b634e487b7160e01b87526032600452602487fd5b9096508281813d8311612a73575b612a5f8183612dbd565b81010312612a6f57519538612933565b8580fd5b503d612a55565b6040513d88823e3d90fd5b90508381813d8311612aab575b612a9c8183612dbd565b810103126116c35751386128d6565b503d612a92565b6040513d89823e3d90fd5b634e487b7160e01b84526041600452602484fd5b503461092b578060031936011261092b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461092b578060031936011261092b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461092b578060031936011261092b57602060ff60045460a01c166040519015158152f35b503461092b57602036600319011261092b5760406101009166ffffffffffffff612ba9612c5a565b1681526006602052208054906001808060a01b0391015461ffff908060f81c9260405194818116865260a01c60208601528116604085015263ffffffff8160a01c16606085015262ffffff8160c01c166080850152818160d81c1660a085015260e81c1660c0830152612c1b81612c70565b60e0820152f35b9050346109275760203660031901126109275760043563ffffffff60e01b811680910361090d57630271189760e51b14815260209150f35b6004359066ffffffffffffff821682036106d557565b60041115612c7a57565b634e487b7160e01b600052602160045260246000fd5b600435906001600160a01b03821682036106d557565b602435906001600160a01b03821682036106d557565b6000915b60038310612ccd57505050565b60019061ffff83511681526020809101920192019190612cc0565b9181601f840112156106d5578235916001600160401b0383116106d5576020808501948460051b0101116106d557565b60406003198201126106d5576001600160401b03916004358381116106d55782612d4491600401612ce8565b939093926024359182116106d557612d5e91600401612ce8565b9091565b9181601f840112156106d5578235916001600160401b0383116106d557602083818601950101116106d557565b6001600160401b03811161091157604052565b606081019081106001600160401b0382111761091157604052565b90601f801991011681019081106001600160401b0382111761091157604052565b359061ffff821682036106d557565b6000546001600160a01b03163303612e0157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b15612e4c57565b60405162461bcd60e51b81526020600482015260126024820152710416d6f756e742063616e6e6f7420626520360741b6044820152606490fd5b8115612e90570690565b634e487b7160e01b600052601260045260246000fd5b8115612e90570490565b91908201809211612ebd57565b634e487b7160e01b600052601160045260246000fd5b3d15612f0d573d906001600160401b0382116109115760405191612f01601f8201601f191660200184612dbd565b82523d6000602084013e565b606090565b60ff60005460a01c16612f2157565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b600260015414612f6a576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b6040516323b872dd60e01b602082019081526001600160a01b0393841660248301529383166044820152606480820195909552938452919260a08101926001600160401b0392908385118386101761091157169160e082019081118482101761091157604052602083527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656460c08201525161305b93600091829182855af1613055612ed3565b916130fb565b80519081159182156130c9575b50501561307157565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b6130dc92506020809183010191016130e3565b3880613068565b908160209103126106d5575180151581036106d55790565b9192901561315d575081511561310f575090565b3b156131185790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156131705750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b8285106131b6575050604492506000838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350613193565b908160209103126106d557516001600160a01b03811681036106d55790565b156131f557565b60405162461bcd60e51b815260206004820152601860248201527f4e6f742061207065726d6974746564206f70657261746f7200000000000000006044820152606490fd5b1561324157565b60405162461bcd60e51b81526020600482015260116024820152704d69736d6174636865642061727261797360781b6044820152606490fd5b919081101561328a5760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160a01b03811681036106d55790565b6001600160401b0381116109115760051b60200190565b805182101561328a5760209160051b010190565b906132e9826132b4565b6132f66040519182612dbd565b8281528092613307601f19916132b4565b0190602036910137565b90604051915461ffff908181168452818160101c16602085015260201c16604083015261333d82612da2565b565b90600381101561328a5760051b0190565b90600091825b600381106133645750505090565b61ffff80613372838561333f565b511661338b575b506000198114612ebd57600101613356565b600194506001600160a01b03906133a2838561333f565b51169060408051906331a9108f60e11b82526004938483015260209160249383828681847f0000000000000000000000000000000000000000000000000000000000000000165afa91821561346357600092613444575b5080891691160361340c57505050613379565b5162461bcd60e51b8152928301526016908201527508298a840deeedccae4e6d0d2e040dad2e6dac2e8c6d60531b6044820152606490fd5b61345c919250843d861161076f576107618183612dbd565b90386133f9565b83513d6000823e3d90fdfeda731af0442deb99acfb8a71081bbcca0a502becbe49a7ba548146cace38354fa2646970667358221220d2cb12bef340931206d1fd435bebe83e201399d0c3141760a6ced00986f73e3b64736f6c6343000815003300000000000000000000000000000000000000000000000000354a6ba7a18000000000000000000000000000000000000000000000000001158e460913d00000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000038d7ea4c6800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000001275000000000000000000000000004d224452801aced8b2f0aebe155379bb5d594381000000000000000000000000bf42c1972877f39e102807e5e80ed2ff5d16aa5f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000749f5ddf5ab4c1f26f74560a78300563c34b417d0000000000000000000000002a06d1a2939a3dd67baf883062563a4ff1d10239000000000000000000000000734dabe2171dfa9689e94675cc279aa0d3ce7033

Deployed Bytecode

0x608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612c225750806303f153fd14612b815780630e36af7614612b5b57806310c85a3614612b165780631b5d145d14612ad15780631ce9029d146128315780631d8344091461280b5780632938a94f1461272d578063326f823f14612586578063358b81661461254d57806339f68f301461239f5780633a67a0f6146123765780633bf47720146123505780633d2cf8b2146123295780633e08409e146121755780633f4ba83a146120c1578063413fb05a14611fde5780634554f82a14611ec85780635c975abb14611ea35780635f81d91c14611dda5780636d8c6b4714611db1578063715018a614611d57578063718da7ee14611d1257806373f0f4cc14611cc25780638234228014611b775780638456cb5914611aef5780638da5cb5b14611ac85780638f0fd1ee14611a8357806394e989d11461192d5780639a80c4a1146118a2578063ab45ee7d14611816578063ad5c4648146117d1578063af35c6c7146117a2578063bc197c81146116f3578063c7042e52146116c7578063c969a67a1461146a578063cf171e1d146113a7578063cfa5f02a14611277578063d2f7265a14611212578063db928dd0146110e2578063e264172c146110aa578063f23a6e6114610ed2578063f2fde38b14610e0c578063f7260d3e14610de3578063fa9232701461092e5763fed2773c1461021b57600080fd5b3461092b5761010080600319360112610927576040519081018181106001600160401b0382111761091157604052610251612c90565b81526024356001600160601b03811681036106d55760208201526044356001600160a01b03811681036106d557604082015260643563ffffffff811681036106d557606082015262ffffff60843516608435036106d557608435608082015261ffff60a4351660a435036106d55760a43560a082015260c43561ffff811681036106d55760c082015260e435600481101561090d5760e08201526102f3612f59565b6102fb612f12565b80516001600160a01b031633036108be5761ffff60a082015116600181101590816108b1575b50156108755761ffff60c08201511660018110159081610868575b501561082b576001600160601b036020820151166002549066ffffffffffffff8260b81c16116107e65760a08201516040516331a9108f60e11b815261ffff90911660048201526020816024816001600160a01b037f000000000000000000000000749f5ddf5ab4c1f26f74560a78300563c34b417d165afa9081156106e25784916107c7575b50336001600160a01b03909116036107765760c08201516040516331a9108f60e11b815261ffff90911660048201526020816024816001600160a01b037f000000000000000000000000749f5ddf5ab4c1f26f74560a78300563c34b417d165afa9081156106e2578491610747575b5060408301516001600160a01b039081169116036106f4576001600160601b0360648166ffffffffffffff8460801c1693816020870151169060f81c021604168181106000146106ed57505b604051636eb1769f60e11b8152336004820152306024820152906020826044816001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2165afa9182156106e25784926106a9575b506001600160601b0360208401511601116106645763ffffffff61053e8160045462ffffff60c81b600162ffffff8360c81c160160c81b169062ffffff60c81b1916178060045562ffffff8160c81c166080860152600160e086015260a81c1642612eb0565b16606082015262ffffff608082015116825260066020526040822060018060a01b038251166001600160601b0360a01b602084015160a01b161781556001808060a01b0360408401511663ffffffff60a01b606085015160a01b169062ffffff60c01b608086015160c01b1661ffff60d81b60a087015160d81b169061ffff60e81b60c088015160e81b169260e08801516105d881612c70565b6105e181612c70565b60ff60f81b9060f81b1694171717171791015562ffffff60808201511660018060a01b03825116907fbf40ec660247b3a483581bc742d72136a0f24b16506250925c2af28f821d8427604060018060a01b0381860151169463ffffffff60606001600160601b036020840151169201511682519182526020820152a46001805580f35b60405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e74205745544820616c6c6f77616e636500000000006044820152606490fd5b9091506020813d6020116106da575b816106c560209383612dbd565b810103126106d5575190386104d8565b600080fd5b3d91506106b8565b6040513d86823e3d90fd5b905061047e565b60405162461bcd60e51b815260206004820152602560248201527f53656c6c657220646f6573206e6f74206f776e20746865207370656369666965604482015264190810531560da1b6064820152608490fd5b610769915060203d60201161076f575b6107618183612dbd565b8101906131cf565b38610432565b503d610757565b60405162461bcd60e51b8152602060048201526024808201527f427579657220646f6573206e6f74206f776e20746865207370656369666965646044820152630810531560e21b6064820152608490fd5b6107e0915060203d60201161076f576107618183612dbd565b386103c3565b60405162461bcd60e51b815260206004820152601d60248201527f4f7264657220616d6f756e742069732062656c6f77206d696e696d756d0000006044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081cd95b1b195c88105315081251605a1b6044820152606490fd5b617530915011153861033c565b60405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a5908189d5e595c8810531508125160621b6044820152606490fd5b6175309150111538610321565b60405162461bcd60e51b815260206004820152602160248201527f4275796572206d75737420637265617465207468656972206f776e206f7264656044820152603960f91b6064820152608490fd5b8280fd5b634e487b7160e01b600052604160045260246000fd5b5080fd5b80fd5b503461092b5761014036600319011261092b5760405160c081018181106001600160401b0382111761091157604052610965612c90565b815236604312156106d55760405161097c81612da2565b806084913683116106d5576024905b838210610dcb57505060208301523660a312156106d5576040516109ae81612da2565b8060e4923684116106d557905b838210610db35750506040830152356001600160a01b03811681036106d5576060820152610104356001600160481b03811681036106d55760808201526101243562ffffff811681036106d55760a0820152610a15612f59565b610a1d612f12565b80516001600160a01b03163303610d6e576001600160481b036080820151166002549066ffffffffffffff90818360b81c1611610d2a57610a62336020850151613350565b15610cec57610a82604084015160018060a01b0360608601511690613350565b15610ca75760646001600160481b0380928460801c1693816080870151169060f81c02160416818110600014610ca057505b62ffffff6004548160e01b6001838360e01c160160e01b16908260e01b1916178060045560e01c168060a0840152835260076020526040832060018060a01b0383511690816001600160601b0360a01b82541617815560208401518590865b60038110610c6f575050600182015560408401518590865b60038110610c3e57505060028201556060840151608085015160a08681015191901b68ffffffffffffffffff60a01b166001600160a01b039283161760e89190911b6001600160e81b031916176003928301559054610bd8927f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2929091610bb6918691168385612faf565b60018060a01b03606086015116906001600160481b0360808701511692612faf565b62ffffff60a0830151167f514dd9353fa8ce618d8f1d8f37426441258fb5f94216c91926fbf561e09f0e6e604060018060a01b03855116936001600160481b03608060018060a01b03606089015116970151169082519182526020820152a46001805580f35b90916020610c6660019261ffff8651169085851b60031b9161ffff809116831b921b19161790565b93019101610b2b565b90916020610c9760019261ffff8651169085851b60031b9161ffff809116831b921b19161790565b93019101610b13565b9050610ab4565b60405162461bcd60e51b815260206004820152601760248201527f53656c6c65723a206e6f2076616c696420414c542049440000000000000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275109d5e595c8e881b9bc81d985b1a590810531508125160521b6044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f5472616e7366657220616d6f756e742069732062656c6f77206d696e696d756d6044820152fd5b60405162461bcd60e51b815260206004820152601b60248201527f4275796572206d75737420637265617465206f776e206f7264657200000000006044820152606490fd5b60208091610dc084612dde565b8152019101906109bb565b60208091610dd884612dde565b81520191019061098b565b503461092b578060031936011261092b576003546040516001600160a01b039091168152602090f35b503461092b57602036600319011261092b57610e26612c90565b610e2e612ded565b6001600160a01b03908116908115610e7e57600054826001600160601b0360a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b503461092b5760a036600319011261092b57610eec612c90565b50610ef5612ca6565b6044356064356084356001600160401b0381116110a657610f1a903690600401612d62565b50506001600160a01b037f000000000000000000000000bf42c1972877f39e102807e5e80ed2ff5d16aa5f811693909290338503611061578161101c5760038694610f6d60ff60025460f01c1686612ea6565b9216808652600560205260408620610f86848254612eb0565b9055808652600560205260008051602061346f8339815191526040808820548151908882526020820152a4833b1561090d57606490836040519586948593637a94c56560e11b8552306004860152602485015260448401525af1801561101157610ffd575b60405163f23a6e6160e01b8152602090f35b6110078291612d8f565b61092b5780610feb565b6040513d84823e3d90fd5b60405162461bcd60e51b815260206004820152601b60248201527f4f6e6c792052564d20746f6b656e4964203020616363657074656400000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601860248201527f4f6e6c792052564d20746f6b656e7320616363657074656400000000000000006044820152606490fd5b8480fd5b503461092b578060031936011261092b576110c3612ded565b8080808060018060a01b0381541647905af1506110de612ed3565b5080f35b503461092b578060031936011261092b576110fb612ded565b80546040516370a0823160e01b81523060048201526020916001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281169291168382602481865afa90811561120757849286926111d4575b5060405163a9059cbb60e01b81526001600160a01b0390911660048201526024810191909152918290818681604481015b03925af180156111c95761119c578280f35b816111bb92903d106111c2575b6111b38183612dbd565b8101906130e3565b5038808280f35b503d6111a9565b6040513d85823e3d90fd5b8381949293503d8311611200575b6111ec8183612dbd565b810103126106d5579051839161118a611159565b503d6111e2565b6040513d87823e3d90fd5b503461092b578060031936011261092b5760c060025466ffffffffffffff90604051916001600160481b0382168352808260481c166020840152808260801c1660408401528160b81c16606083015260ff8160f01c16608083015260f81c60a0820152f35b508060031936011261092b5761128b612f59565b611293612f12565b61129e341515612e45565b66ffffffffffffff60025460481c166112b78134612e86565b61136d576112c59034612ea6565b3382526005602052604082206112dc828254612eb0565b9055818080803460018060a01b03600354165af16112f8612ed3565b501561133357338252600560205281604081205460405190348252602082015260008051602061346f83398151915260403392a46001805580f35b60405162461bcd60e51b815260206004820152601260248201527108cc2d2d8cac840e8de40e6cadcc8408aa8960731b6044820152606490fd5b60405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a590811551208185b5bdd5b9d60721b6044820152606490fd5b503461092b5760c036600319011261092b576113c1612c5a565b6024356001600160481b0381168091036106d5576044359060ff821682036106d55760643560ff811681036106d55766ffffffffffffff91608435838116036106d55760a43592831683036106d557611418612ded565b6fffffffffffffff00000000000000000060ff60f81b8360f81b169560481b16179060ff60801b9060801b16179066ffffffffffffff60b81b9060b81b16179060ff60f01b9060f01b16171760025580f35b503461092b57608036600319011261092b57611484612c90565b66ffffffffffffff91906024358381168082036106d557604435908582168092036106d55760643590811590811583036116c35783811161168e57830387811161167a5760019794939291908516880185811161166657856114ec91999799989698166132df565b978594875b61157c575b5050505050611504816132df565b94825b828110611551575050506040519260208085019181865286518093528160408701970193905b83821061153a5786880387f35b84518116885296820196938201939085019061152d565b938486611563839997859997996132cb565b511661156f82886132cb565b5201959395949294611507565b90888783828b9d9b989796959c9a9c16878111611657578689809482611631575b82156115fc575b826115d7575b50506115c3575b500116909192939497999896986114f1565b6115d0838b019a8d6132cb565b52386115b1565b6040919250838152600660205220015460f81c6115f381612c70565b1515838e6115aa565b9150878061160b575b916115a4565b5050819052600660205260408d20548d9084906001600160a01b03888116911614611605565b8390525050600660205260408d208301546001600160a01b03868116911614838e61159d565b505050509896989795976114f6565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b87526011600452602487fd5b60405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642072616e676560981b6044820152606490fd5b8680fd5b503461092b578060031936011261092b576116e0612ded565b600480546001600160a01b031916905580f35b503461092b5760a036600319011261092b5761170d612c90565b50611716612ca6565b506001600160401b0360443581811161090d57611737903690600401612ce8565b505060643581811161090d57611751903690600401612ce8565b50506084359081116109275761176b903690600401612d62565b505060405162461bcd60e51b815260206004820152600d60248201526c139bdd081cdd5c1c1bdc9d1959609a1b6044820152606490fd5b503461092b578060031936011261092b576117bb612ded565b6004805460ff60a01b1916600160a01b17905580f35b503461092b578060031936011261092b576040517f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168152602090f35b503461092b57602036600319011261092b57611830612c90565b611838612ded565b6001600160a01b0316801561185d576001600160601b0360a01b600454161760045580f35b60405162461bcd60e51b815260206004820152601f60248201527f4f70657261746f7220616464726573732063616e6e6f74206265206e756c6c006044820152606490fd5b503461092b576118b136612d18565b90929160018060a01b0391826004541633148015611921575b6118d3906131ee565b6118de81831461323a565b855b8281106118eb578680f35b806118f9600192848961327a565b358561190e61190984888b61327a565b6132a0565b16895260056020526040892055016118e0565b508554831633146118ca565b503461092b57602036600319011261092b5760043561194a612f59565b611952612f12565b61195d811515612e45565b60ff60025460f01c166119708183612e86565b611a495761197e9082612ea6565b90338352600560205260408320611996838254612eb0565b9055827f000000000000000000000000bf42c1972877f39e102807e5e80ed2ff5d16aa5f6001600160a01b0316803b15610927578190606460405180948193637a94c56560e11b83523360048401528160248401528760448401525af180156106e257611a35575b5060039033845260056020526040842054604051918252602082015260008051602061346f83398151915260403392a46001805580f35b92611a4260039294612d8f565b92906119fe565b60405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a590814959348185b5bdd5b9d60721b6044820152606490fd5b503461092b578060031936011261092b576040517f000000000000000000000000749f5ddf5ab4c1f26f74560a78300563c34b417d6001600160a01b03168152602090f35b503461092b578060031936011261092b57546040516001600160a01b039091168152602090f35b503461092b578060031936011261092b57600454611b2290336001600160a01b0391821614908115611b6a575b506131ee565b611b2a612f12565b805460ff60a01b1916600160a01b1781556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602090a180f35b9050825416331438611b1c565b503461092b57611b8636612d18565b9160018060a09593951b0390816004541633148015611cb6575b611ba9906131ee565b611bb484821461323a565b855b818110611bc1578680f35b86611bcd82878961327a565b351315611c0b5780611be2600192878961327a565b3584611bf261190984878a61327a565b1689526005602052604089209081540190555b01611bb6565b82611c1a61190983858861327a565b16875260056020908082526040892054611c3584898b61327a565b358a0311611c7157908291611c4d600194898b61327a565b359186611c5e61190986898c61327a565b168b525260408920908154019055611c05565b60405162461bcd60e51b815260048101839052601a60248201527f43616e6e6f742064656372656173652062656c6f77207a65726f0000000000006044820152606490fd5b50855482163314611ba0565b503461092b57602036600319011261092b5760043563ffffffff8116810361092757611cec612ded565b6004805463ffffffff60a81b191660a89290921b63ffffffff60a81b1691909117905580f35b503461092b57602036600319011261092b576004356001600160a01b0381169081900361092757611d41612ded565b6001600160601b0360a01b600354161760035580f35b503461092b578060031936011261092b57611d70612ded565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461092b578060031936011261092b576004546040516001600160a01b039091168152602090f35b503461092b57602036600319011261092b576004356001600160601b038116809103610927576101409160409160608351611e1481612da2565b36903760608351611e2481612da2565b3690378152600760205220805460038201546001600160a01b03918216926001600160481b039290611e8690611e7c611e6b6002611e6460018501613311565b9301613311565b916040519788526020880190612cbc565b6080860190612cbc565b811660e08401528060e81c61010084015260a01c16610120820152f35b503461092b578060031936011261092b5760ff6020915460a01c166040519015158152f35b503461092b57602036600319011261092b57600435611ee5612f59565b611eed612f12565b611ef8811515612e45565b6001600160481b0360025416611f0e8183612e86565b611fa457611f1e60029183612ea6565b91338452600560205260408420611f36848254612eb0565b9055600354611f719082906001600160a01b0316337f0000000000000000000000004d224452801aced8b2f0aebe155379bb5d594381612faf565b33845260056020526040842054604051918252602082015260008051602061346f83398151915260403392a46001805580f35b60405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a590810541148185b5bdd5b9d60721b6044820152606490fd5b503461092b57602036600319011261092b57600435611ffb612f59565b612003612f12565b61200e811515612e45565b66ffffffffffffff60025460481c166120278183612e86565b6120865761203760019183612ea6565b9133845260056020526040842061204f848254612eb0565b9055611f7181838060a01b0360035416337f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2612faf565b60405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a590815d1551208185b5bdd5b9d606a1b6044820152606490fd5b503461092b578060031936011261092b576004546120f390336001600160a01b0391821614908115611b6a57506131ee565b805460ff8160a01c16156121395760ff60a01b191681556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a180f35b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b503461092b576020806003193601126109275766ffffffffffffff612198612c5a565b6121a0612f59565b6121a8612f12565b169081835260068152604083209160018301918254938460f81c6121cb81612c70565b80156122ed57806121dd600192612c70565b036122b15754936001600160a01b038086169490919033861480156122a4575b8015612298575b15612253576001600160f81b038216600360f81b17905560405160a09690961c865216937f57ecb4ac08f8d8a76afc3b4d54c62085a1087af5c0e23c6e9c485565878cfd269190a46001805580f35b60405162461bcd60e51b815260048101859052601b60248201527f4e6f7420746865206275796572206f662074686973206f7264657200000000006044820152606490fd5b50338389541614612204565b50338360045416146121fd565b60405162461bcd60e51b81526004810183905260146024820152734f72646572206973206e6f742070656e64696e6760601b6044820152606490fd5b60405162461bcd60e51b815260048101849052601460248201527313dc99195c88191bd95cc81b9bdd08195e1a5cdd60621b6044820152606490fd5b503461092b578060031936011261092b57602063ffffffff60045460a81c16604051908152f35b503461092b578060031936011261092b57602062ffffff60045460e01c16604051908152f35b503461092b578060031936011261092b5761238f612ded565b6004805460ff60a01b1916905580f35b503461092b57602036600319011261092b576123b9612c5a565b6004546001600160a01b039190821633148015612541575b6123da906131ee565b66ffffffffffffff80911691828452600660205260408420906001820192835460018160f81c61240981612c70565b036124f15760a01c63ffffffff1642116124c2576124809254918260a01c926002549260648460f81c8602049360801c168084106124ba575b508116906124777f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29382600354168486612faf565b85541691612faf565b80546001600160f81b0316600160f91b1790557f0e69115e81cc62141207a4e223b36a112153d2040b6ee2c0cf3040d3cec0d64e8280a280f35b925081612442565b60405162461bcd60e51b8152602060048201526007602482015266115e1c1a5c995960ca1b6044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f4f72646572206e6f7420656c696769626c6520666f722066756c66696c6c6d656044820152611b9d60f21b6064820152608490fd5b508254821633146123d1565b503461092b57602036600319011261092b576020906040906001600160a01b03612575612c90565b168152600583522054604051908152f35b503461092b57604036600319011261092b576125a0612c90565b602435906125ac612f59565b6125b4612f12565b60ff60045460a01c16156126e9576001600160a01b03169081156126a45733835260056020528060408420541061265f5733835260056020526040832080549082820391821161264b5755818352600560205260408320612616828254612eb0565b90556040519081527f1939c1072ace2dbc5fa27e183bfe1df83062209fe28d9f01a477f503ee75a25060203392a36001805580f35b634e487b7160e01b85526011600452602485fd5b60405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e7420706f696e74732062616c616e636500000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527f43616e6e6f742073656e6420746f207a65726f206164647265737300000000006044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f5472616e7366657273206f6620706f696e7473206172652064697361626c65646044820152fd5b503461092b578060031936011261092b57612746612ded565b80546040516370a0823160e01b81523060048201526020916001600160a01b037f0000000000000000000000004d224452801aced8b2f0aebe155379bb5d59438181169291168382602481865afa90811561120757849286926127d8575060405163a9059cbb60e01b81526001600160a01b03909116600482015260248101919091529182908186816044810161118a565b8381949293503d8311612804575b6127f08183612dbd565b810103126110a6579051839161118a611159565b503d6127e6565b503461092b578060031936011261092b57602062ffffff60045460c81c16604051908152f35b503461092b576020908160031936011261092b5761284d612c90565b91604051608081018181106001600160401b03821117612abd5760405260038152818101916060368437604051636eb1769f60e11b8082526001600160a01b03878116600484015230602484015290969183816044817f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc286165afa908115612ab2578791612a85575b50845115612a335785526040519687526001600160a01b038216600488015230602488015282876044817f0000000000000000000000004d224452801aced8b2f0aebe155379bb5d59438185165afa968715612a7a578697612a47575b50835196600197881015612a33576040858101919091525163e985e9c560e01b81526001600160a01b039290921660048301523060248301528290829060449082907f000000000000000000000000bf42c1972877f39e102807e5e80ed2ff5d16aa5f165afa908115611207578591612a16575b5015612a1057845b8251600210156129fc5785919260ff86921660608201526040519380850191818652518092526040850195925b8281106129e95785870386f35b83518752958101959281019284016129dc565b634e487b7160e01b85526032600452602485fd5b836129af565b612a2d9150823d84116111c2576111b38183612dbd565b386129a7565b634e487b7160e01b87526032600452602487fd5b9096508281813d8311612a73575b612a5f8183612dbd565b81010312612a6f57519538612933565b8580fd5b503d612a55565b6040513d88823e3d90fd5b90508381813d8311612aab575b612a9c8183612dbd565b810103126116c35751386128d6565b503d612a92565b6040513d89823e3d90fd5b634e487b7160e01b84526041600452602484fd5b503461092b578060031936011261092b576040517f0000000000000000000000004d224452801aced8b2f0aebe155379bb5d5943816001600160a01b03168152602090f35b503461092b578060031936011261092b576040517f000000000000000000000000bf42c1972877f39e102807e5e80ed2ff5d16aa5f6001600160a01b03168152602090f35b503461092b578060031936011261092b57602060ff60045460a01c166040519015158152f35b503461092b57602036600319011261092b5760406101009166ffffffffffffff612ba9612c5a565b1681526006602052208054906001808060a01b0391015461ffff908060f81c9260405194818116865260a01c60208601528116604085015263ffffffff8160a01c16606085015262ffffff8160c01c166080850152818160d81c1660a085015260e81c1660c0830152612c1b81612c70565b60e0820152f35b9050346109275760203660031901126109275760043563ffffffff60e01b811680910361090d57630271189760e51b14815260209150f35b6004359066ffffffffffffff821682036106d557565b60041115612c7a57565b634e487b7160e01b600052602160045260246000fd5b600435906001600160a01b03821682036106d557565b602435906001600160a01b03821682036106d557565b6000915b60038310612ccd57505050565b60019061ffff83511681526020809101920192019190612cc0565b9181601f840112156106d5578235916001600160401b0383116106d5576020808501948460051b0101116106d557565b60406003198201126106d5576001600160401b03916004358381116106d55782612d4491600401612ce8565b939093926024359182116106d557612d5e91600401612ce8565b9091565b9181601f840112156106d5578235916001600160401b0383116106d557602083818601950101116106d557565b6001600160401b03811161091157604052565b606081019081106001600160401b0382111761091157604052565b90601f801991011681019081106001600160401b0382111761091157604052565b359061ffff821682036106d557565b6000546001600160a01b03163303612e0157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b15612e4c57565b60405162461bcd60e51b81526020600482015260126024820152710416d6f756e742063616e6e6f7420626520360741b6044820152606490fd5b8115612e90570690565b634e487b7160e01b600052601260045260246000fd5b8115612e90570490565b91908201809211612ebd57565b634e487b7160e01b600052601160045260246000fd5b3d15612f0d573d906001600160401b0382116109115760405191612f01601f8201601f191660200184612dbd565b82523d6000602084013e565b606090565b60ff60005460a01c16612f2157565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b600260015414612f6a576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b6040516323b872dd60e01b602082019081526001600160a01b0393841660248301529383166044820152606480820195909552938452919260a08101926001600160401b0392908385118386101761091157169160e082019081118482101761091157604052602083527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656460c08201525161305b93600091829182855af1613055612ed3565b916130fb565b80519081159182156130c9575b50501561307157565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b6130dc92506020809183010191016130e3565b3880613068565b908160209103126106d5575180151581036106d55790565b9192901561315d575081511561310f575090565b3b156131185790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156131705750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b8285106131b6575050604492506000838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350613193565b908160209103126106d557516001600160a01b03811681036106d55790565b156131f557565b60405162461bcd60e51b815260206004820152601860248201527f4e6f742061207065726d6974746564206f70657261746f7200000000000000006044820152606490fd5b1561324157565b60405162461bcd60e51b81526020600482015260116024820152704d69736d6174636865642061727261797360781b6044820152606490fd5b919081101561328a5760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160a01b03811681036106d55790565b6001600160401b0381116109115760051b60200190565b805182101561328a5760209160051b010190565b906132e9826132b4565b6132f66040519182612dbd565b8281528092613307601f19916132b4565b0190602036910137565b90604051915461ffff908181168452818160101c16602085015260201c16604083015261333d82612da2565b565b90600381101561328a5760051b0190565b90600091825b600381106133645750505090565b61ffff80613372838561333f565b511661338b575b506000198114612ebd57600101613356565b600194506001600160a01b03906133a2838561333f565b51169060408051906331a9108f60e11b82526004938483015260209160249383828681847f000000000000000000000000749f5ddf5ab4c1f26f74560a78300563c34b417d165afa91821561346357600092613444575b5080891691160361340c57505050613379565b5162461bcd60e51b8152928301526016908201527508298a840deeedccae4e6d0d2e040dad2e6dac2e8c6d60531b6044820152606490fd5b61345c919250843d861161076f576107618183612dbd565b90386133f9565b83513d6000823e3d90fdfeda731af0442deb99acfb8a71081bbcca0a502becbe49a7ba548146cace38354fa2646970667358221220d2cb12bef340931206d1fd435bebe83e201399d0c3141760a6ced00986f73e3b64736f6c63430008150033

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

00000000000000000000000000000000000000000000000000354a6ba7a18000000000000000000000000000000000000000000000000001158e460913d00000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000038d7ea4c6800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000001275000000000000000000000000004d224452801aced8b2f0aebe155379bb5d594381000000000000000000000000bf42c1972877f39e102807e5e80ed2ff5d16aa5f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000749f5ddf5ab4c1f26f74560a78300563c34b417d0000000000000000000000002a06d1a2939a3dd67baf883062563a4ff1d10239000000000000000000000000734dabe2171dfa9689e94675cc279aa0d3ce7033

-----Decoded View---------------
Arg [0] : _rateEth (uint56): 15000000000000000
Arg [1] : _rateApe (uint72): 20000000000000000000
Arg [2] : _rateRvm (uint8): 1
Arg [3] : _minFee (uint56): 1000000000000000
Arg [4] : _minOrder (uint56): 1000000000000000
Arg [5] : _fee (uint8): 5
Arg [6] : _expiryPeriod (uint32): 1209600
Arg [7] : _ape (address): 0x4d224452801ACEd8B2F0aebE155379bb5D594381
Arg [8] : _rvm (address): 0xbF42C1972877F39e102807E5E80ed2ff5D16aa5f
Arg [9] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [10] : _alts (address): 0x749f5Ddf5Ab4c1F26f74560A78300563C34B417d
Arg [11] : _permittedOperator (address): 0x2A06D1A2939a3DD67Baf883062563A4FF1D10239
Arg [12] : _receiver (address): 0x734dABe2171Dfa9689E94675Cc279aA0d3Ce7033

-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000354a6ba7a18000
Arg [1] : 000000000000000000000000000000000000000000000001158e460913d00000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [3] : 00000000000000000000000000000000000000000000000000038d7ea4c68000
Arg [4] : 00000000000000000000000000000000000000000000000000038d7ea4c68000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [6] : 0000000000000000000000000000000000000000000000000000000000127500
Arg [7] : 0000000000000000000000004d224452801aced8b2f0aebe155379bb5d594381
Arg [8] : 000000000000000000000000bf42c1972877f39e102807e5e80ed2ff5d16aa5f
Arg [9] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [10] : 000000000000000000000000749f5ddf5ab4c1f26f74560a78300563c34b417d
Arg [11] : 0000000000000000000000002a06d1a2939a3dd67baf883062563a4ff1d10239
Arg [12] : 000000000000000000000000734dabe2171dfa9689e94675cc279aa0d3ce7033


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.