false
true
0

Contract Address Details

0x000000512EfeFc2Bce764a6690C87C83B6253FE0

Contract Name
SizeSealed
Creator
0x000000–439497 at 0x3805f5–58168d
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
26347944
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
SizeSealed




Optimization enabled
true
Compiler version
v0.8.19+commit.7dd6d404




Optimization runs
1000000
EVM Version
london




Verified at
2026-04-22T01:58:50.397127Z

src/SizeSealed.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;

import {ERC20} from "solmate/tokens/ERC20.sol";
import {MerkleProofLib} from "solmate/utils/MerkleProofLib.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";

import {ECCMath} from "./util/ECCMath.sol";
import {ISizeSealed} from "./interfaces/ISizeSealed.sol";
import {CommonTokenMath} from "./util/CommonTokenMath.sol";

/// @title Size Sealed Auction
/// @author Size Market
contract SizeSealed is ISizeSealed {
    ///////////////////////////////
    ///          STATE          ///
    ///////////////////////////////

    uint256 public currentAuctionId;

    mapping(uint256 => Auction) public idToAuction;

    ///////////////////////////////////////////////////
    ///                  MODIFIERS                  ///
    ///////////////////////////////////////////////////

    modifier atState(Auction storage a, States _state) {
        if (block.timestamp < a.timings.startTimestamp) {
            if (_state != States.Created) revert InvalidState();
        } else if (block.timestamp < a.timings.endTimestamp) {
            if (_state != States.AcceptingBids) revert InvalidState();
        } else if (a.data.finalized) {
            if (_state != States.Finalized) revert InvalidState();
        } else if (block.timestamp <= a.timings.endTimestamp + 24 hours) {
            if (_state != States.RevealPeriod) revert InvalidState();
        } else if (block.timestamp > a.timings.endTimestamp + 24 hours) {
            if (_state != States.Voided) revert InvalidState();
        } else {
            revert();
        }
        _;
    }

    ///////////////////////////////////////////////////////////////////////
    ///                          AUCTION LOGIC                          ///
    ///////////////////////////////////////////////////////////////////////

    /// @notice Creates a new sealed auction
    /// @dev Transfers the `baseToken` from `msg.sender` to the contract
    /// @return `auctionId` unique to that auction
    /// @param auctionParams Parameters used during the auction
    /// @param timings The timestamps at which the auction starts/ends
    /// @param encryptedSellerPrivKey Encrypted seller's ephemeral private key
    function createAuction(
        AuctionParameters calldata auctionParams,
        Timings calldata timings,
        bytes calldata encryptedSellerPrivKey
    ) external returns (uint256) {
        if (timings.endTimestamp <= block.timestamp) {
            revert InvalidTimestamp();
        }
        if (timings.startTimestamp >= timings.endTimestamp) {
            revert InvalidTimestamp();
        }
        if (timings.endTimestamp > timings.vestingStartTimestamp) {
            revert InvalidTimestamp();
        }
        if (timings.vestingStartTimestamp > timings.vestingEndTimestamp) {
            revert InvalidTimestamp();
        }
        if (timings.cliffPercent > 1e18) {
            revert InvalidCliffPercent();
        }
        // Revert if the min bid is more than the total reserve of the auction
        if (
            FixedPointMathLib.mulDivDown(
                auctionParams.minimumBidQuote, type(uint128).max, auctionParams.totalBaseAmount
            ) > auctionParams.reserveQuotePerBase
        ) {
            revert InvalidReserve();
        }
        // Passes https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol#L9
        if (auctionParams.quoteToken.code.length == 0 || auctionParams.baseToken.code.length == 0) {
            revert TokenDoesNotExist();
        }

        uint256 auctionId = ++currentAuctionId;

        Auction storage a = idToAuction[auctionId];
        a.timings = timings;

        a.data.seller = msg.sender;

        a.params = auctionParams;

        // Transfer base tokens from the seller
        transferWithTaxCheck(auctionParams.baseToken, msg.sender, auctionParams.totalBaseAmount);

        emit AuctionCreated(auctionId, msg.sender, auctionParams, timings, encryptedSellerPrivKey);

        return auctionId;
    }

    /// @dev Transfers `amount` from msg.sender, and checks that the amount transferred matches the expected
    function transferWithTaxCheck(address token, address from, uint256 amount) internal {
        uint256 balanceBeforeTransfer = ERC20(token).balanceOf(address(this));

        SafeTransferLib.safeTransferFrom(ERC20(token), from, address(this), amount);

        uint256 balanceAfterTransfer = ERC20(token).balanceOf(address(this));
        if (balanceAfterTransfer - balanceBeforeTransfer != amount) {
            revert UnexpectedBalanceChange();
        }
    }

    /// @notice Bid on a runnning auction
    /// @dev Transfers `quoteAmount` of `quoteToken` from bidder to contract
    /// @return Index of the bid
    /// @param auctionId Id of the auction to bid on
    /// @param quoteAmount Amount of `quoteTokens` bidding on a committed amount of `baseTokens`
    /// @param commitment Hash commitment of the `baseAmount`
    /// @param pubKey Public key used to encrypt `baseAmount`
    /// @param encryptedMessage `baseAmount` encrypted to the seller's public key
    /// @param encryptedPrivateKey Encrypted private key for on-chain storage
    /// @param proof Merkle proof that checks seller against `merkleRoot` if there is a whitelist
    function bid(
        uint256 auctionId,
        uint128 quoteAmount,
        bytes32 commitment,
        ECCMath.Point calldata pubKey,
        bytes32 encryptedMessage,
        bytes calldata encryptedPrivateKey,
        bytes32[] calldata proof
    ) external atState(idToAuction[auctionId], States.AcceptingBids) returns (uint256) {
        Auction storage a = idToAuction[auctionId];

        if (a.params.merkleRoot != bytes32(0)) {
            bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
            if (!MerkleProofLib.verify(proof, a.params.merkleRoot, leaf)) {
                revert InvalidProof();
            }
        }

        // Seller cannot bid on their own auction
        if (msg.sender == a.data.seller) {
            revert UnauthorizedCaller();
        }

        if (quoteAmount == 0 || quoteAmount < a.params.minimumBidQuote) {
            revert InvalidBidAmount();
        }

        uint256 bidIndex = a.bids.length;
        // Max of 1000 bids on an auction to prevent DOS
        if (bidIndex >= 1000) {
            revert InvalidState();
        }

        EncryptedBid memory ebid;
        ebid.sender = msg.sender;
        ebid.quoteAmount = quoteAmount;
        ebid.initialIndex = uint128(bidIndex);
        ebid.commitment = commitment;
        ebid.pubKey = pubKey;
        ebid.encryptedMessage = encryptedMessage;

        a.bids.push(ebid);

        // Transfer the quote tokens from the bidder
        transferWithTaxCheck(a.params.quoteToken, msg.sender, quoteAmount);

        emit Bid(
            msg.sender, auctionId, bidIndex, quoteAmount, commitment, pubKey, encryptedMessage, encryptedPrivateKey
        );

        return bidIndex;
    }

    /// @notice Reveals the private key of the seller
    /// @dev All valid bids are decrypted after this
    ///      finalizeBidIndices should be empty if seller does not wish to finalize in this tx
    /// @param privateKey Private key corresponding to the auctions public key
    /// @param finalizeBidIndices Bid indices that will be sent to finalize()
    function reveal(uint256 auctionId, uint256 privateKey, uint256[] calldata finalizeBidIndices)
        external
        atState(idToAuction[auctionId], States.RevealPeriod)
    {
        Auction storage a = idToAuction[auctionId];
        if (a.data.privKey != 0) {
            revert InvalidState();
        }

        ECCMath.Point memory pubKey = ECCMath.publicKey(privateKey);
        if (pubKey.x != a.params.pubKey.x || pubKey.y != a.params.pubKey.y || (pubKey.x == 1 && pubKey.y == 1)) {
            revert InvalidPrivateKey();
        }

        a.data.privKey = privateKey;

        emit RevealedKey(auctionId, privateKey);

        if (finalizeBidIndices.length != 0) {
            finalize(auctionId, finalizeBidIndices);
        }
    }

    // Used to get around stack too deep errors -- even with viaIr
    struct FinalizeData {
        uint256 reserveQuotePerBase;
        uint256 totalBaseAmount;
        uint256 previousIndex;
        uint256 previousQuote;
        uint256 previousBase;
        uint256 filledBase;
    }

    /// @notice Finalises an auction by revealing all bids
    /// @dev Calculates the minimum `quotePerBase` and marks successful bids
    /// @param auctionId `auctionId` of the auction to bid on
    /// @param bidIndices Bids sorted by price descending
    function finalize(uint256 auctionId, uint256[] memory bidIndices)
        public
        atState(idToAuction[auctionId], States.RevealPeriod)
    {
        Auction storage a = idToAuction[auctionId];
        uint256 sellerPriv = a.data.privKey;
        if (sellerPriv == 0) {
            revert InvalidPrivateKey();
        }

        if (bidIndices.length != a.bids.length) {
            revert InvalidCalldata();
        }

        FinalizeData memory data;
        data.reserveQuotePerBase = a.params.reserveQuotePerBase;
        data.totalBaseAmount = a.params.totalBaseAmount;
        data.previousQuote = type(uint128).max;
        data.previousBase = 1;

        // Bitmap of all the bid indices that have been processed
        uint256[] memory seenBidMap = new uint256[]((bidIndices.length/256)+1);

        // Fill orders from highest price to lowest price
        for (uint256 i; i < bidIndices.length; i++) {
            uint256 bidIndex = bidIndices[i];
            EncryptedBid storage b = a.bids[bidIndex];

            {
                // Verify this bid index hasn't been seen before
                uint256 bitmapIndex = bidIndex / 256;
                uint256 bitMap = seenBidMap[bitmapIndex];
                uint256 indexBit = 1 << (bidIndex % 256);
                if (bitMap & indexBit == indexBit) revert IncorrectBidIndices();
                seenBidMap[bitmapIndex] = bitMap | indexBit;
            }

            // k1*(G*k2) == k2*(G*k1)
            ECCMath.Point memory sharedPoint = ECCMath.ecMul(b.pubKey, sellerPriv);
            // If the bidder public key isn't on the bn128 curve
            if (sharedPoint.x == 1 && sharedPoint.y == 1) continue;

            bytes32 decryptedMessage = ECCMath.decryptMessage(sharedPoint, b.encryptedMessage);
            // If the bidder didn't faithfully submit commitment or pubkey
            if (computeCommitment(decryptedMessage) != b.commitment) continue;

            // Most significant 128 bits are the base amount
            uint256 baseAmount = uint256(decryptedMessage >> 128);
            uint256 quoteAmount = b.quoteAmount;
            uint256 initialIndex = b.initialIndex;

            if (baseAmount == 0) continue;

            {
                // Verify that bids are sorted by price-time priority
                uint256 currentMult = quoteAmount * data.previousBase;
                uint256 previousMult = data.previousQuote * baseAmount;

                if (currentMult >= previousMult) {
                    // If last bid was the same price, make sure we filled the earliest bid first
                    if (currentMult == previousMult) {
                        if (data.previousIndex > initialIndex) revert InvalidSorting();
                    } else {
                        revert InvalidSorting();
                    }
                }
            }

            // Only fill if above reserve price
            if (FixedPointMathLib.mulDivDown(quoteAmount, type(uint128).max, baseAmount) < data.reserveQuotePerBase) {
                continue;
            }

            // Auction has been fully filled
            if (data.filledBase == data.totalBaseAmount) continue;

            data.previousBase = baseAmount;
            data.previousQuote = quoteAmount;
            data.previousIndex = initialIndex;

            // Fill the remaining unfilled base amount
            if (data.filledBase + baseAmount > data.totalBaseAmount) {
                baseAmount = data.totalBaseAmount - data.filledBase;
            }

            b.filledBaseAmount = uint128(baseAmount);
            data.filledBase += baseAmount;
        }

        a.data.clearingQuote = uint128(data.previousQuote);
        a.data.clearingBase = uint128(data.previousBase);
        a.data.finalized = true;

        // seenBidMap[0:len-1] should be full
        for (uint256 i; i < seenBidMap.length - 1; i++) {
            if (seenBidMap[i] != type(uint256).max) {
                revert IncorrectBidIndices();
            }
        }

        // seenBidMap[-1] should only have the last N bits set
        if (seenBidMap[seenBidMap.length - 1] != (1 << (bidIndices.length % 256)) - 1) {
            revert IncorrectBidIndices();
        }

        // Sanity check that we didn't overfill the auction
        if (data.filledBase > data.totalBaseAmount) {
            revert OverfilledAuction();
        }

        // Transfer the unsold baseToken
        if (data.totalBaseAmount > data.filledBase) {
            uint256 unsoldBase = data.totalBaseAmount - data.filledBase;
            a.params.totalBaseAmount = uint128(data.filledBase);
            safeTransferOut(a.params.baseToken, a.data.seller, unsoldBase);
        }

        // Calculate quote amount based on clearing price
        uint256 filledQuote = FixedPointMathLib.mulDivDown(data.previousQuote, data.filledBase, data.previousBase);

        safeTransferOut(a.params.quoteToken, a.data.seller, filledQuote);

        emit AuctionFinalized(auctionId, bidIndices, data.filledBase, filledQuote);
    }

    /// @notice Called after finalize for unsuccessful bidders to return funds
    /// @dev Returns all `quoteToken` to the original bidder
    /// @param auctionId `auctionId` of the auction to bid on
    /// @param bidIndex Index of the failed bid to be refunded
    function refund(uint256 auctionId, uint256 bidIndex) external atState(idToAuction[auctionId], States.Finalized) {
        Auction storage a = idToAuction[auctionId];
        EncryptedBid storage b = a.bids[bidIndex];
        if (msg.sender != b.sender) {
            revert UnauthorizedCaller();
        }

        if (b.filledBaseAmount != 0) {
            revert InvalidState();
        }

        b.sender = address(0);

        emit BidRefund(auctionId, bidIndex);

        SafeTransferLib.safeTransfer(ERC20(a.params.quoteToken), msg.sender, b.quoteAmount);
    }

    /// @notice Called after finalize for successful bidders
    /// @dev Returns won `baseToken` & any unfilled `quoteToken` to the bidder
    /// @param auctionId `auctionId` of the auction bid on
    /// @param bidIndex Index of the successful bid
    function withdraw(uint256 auctionId, uint256 bidIndex) external atState(idToAuction[auctionId], States.Finalized) {
        Auction storage a = idToAuction[auctionId];
        EncryptedBid storage b = a.bids[bidIndex];
        if (msg.sender != b.sender) {
            revert UnauthorizedCaller();
        }

        uint128 baseAmount = b.filledBaseAmount;
        if (baseAmount == 0) {
            revert InvalidState();
        }

        uint128 baseTokensAvailable = tokensAvailableForWithdrawal(auctionId, baseAmount);
        baseTokensAvailable = baseTokensAvailable - b.baseWithdrawn;

        b.baseWithdrawn += baseTokensAvailable;

        // Refund unfilled quoteAmount on first withdraw
        if (b.quoteAmount != 0) {
            uint256 quoteBought = FixedPointMathLib.mulDivUp(baseAmount, a.data.clearingQuote, a.data.clearingBase);
            // refund = min(quoteAmount, quoteBought)
            uint256 refundedQuote = b.quoteAmount;
            if (refundedQuote >= quoteBought) refundedQuote -= quoteBought;
            else refundedQuote = 0;
            b.quoteAmount = 0;

            safeTransferOut(a.params.quoteToken, msg.sender, refundedQuote);
        }

        safeTransferOut(a.params.baseToken, msg.sender, baseTokensAvailable);

        emit Withdrawal(auctionId, bidIndex, baseTokensAvailable, baseAmount - b.baseWithdrawn);
    }

    /// @dev Transfer amount of token, but cap the amount at the current balance to prevent reverts
    function safeTransferOut(address token, address to, uint256 amount) internal {
        uint256 balance = ERC20(token).balanceOf(address(this));
        if (balance < amount) amount = balance;
        if (amount == 0) return;

        SafeTransferLib.safeTransfer(ERC20(token), to, amount);
    }

    /// @dev Transfers `baseToken` back to seller and will enable withdraws for bidders
    /// @param auctionId `auctionId` of the auction to be canceled
    function cancelAuction(uint256 auctionId) external {
        Auction storage a = idToAuction[auctionId];
        if (msg.sender != a.data.seller) {
            revert UnauthorizedCaller();
        }
        // Only allow cancellations before finalization
        // Equivalent to atState(idToAuction[auctionId], ~STATE_FINALIZED)
        if (a.data.finalized) {
            revert InvalidState();
        }

        // Allowing bidders to cancel bids (withdraw quote)
        // Auction considered forever States.AcceptingBids but nobody can finalize
        a.data.seller = address(0);
        a.timings.endTimestamp = type(uint32).max;

        emit AuctionCanceled(auctionId);

        SafeTransferLib.safeTransfer(ERC20(a.params.baseToken), msg.sender, a.params.totalBaseAmount);
    }

    /// @dev Transfers `quoteToken` back to bidder and prevents bid from being finalised
    /// @param auctionId `auctionId` of the auction to be canceled
    /// @param bidIndex Index of the bid to be canceled
    function cancelBid(uint256 auctionId, uint256 bidIndex) external {
        Auction storage a = idToAuction[auctionId];
        EncryptedBid storage b = a.bids[bidIndex];
        if (msg.sender != b.sender) {
            revert UnauthorizedCaller();
        }

        // Only allow bid cancellations while not finalized or in the reveal period
        if (block.timestamp >= a.timings.endTimestamp) {
            if (a.data.finalized || block.timestamp <= a.timings.endTimestamp + 24 hours) {
                revert InvalidState();
            }
        }
        uint256 refundAmount = b.quoteAmount;

        // Delete the canceled bid, and replace it with the most recent bid
        a.bids[bidIndex] = a.bids[a.bids.length - 1];
        a.bids.pop();

        emit BidCanceled(auctionId, bidIndex);

        SafeTransferLib.safeTransfer(ERC20(a.params.quoteToken), msg.sender, refundAmount);
    }

    ////////////////////////////////////////////////////////////////////////////
    ///                            UTIL FUNCTIONS                            ///
    ////////////////////////////////////////////////////////////////////////////

    /// @notice Calculates available unlocked tokens for an auction
    /// @dev Uses vesting parameters to account for cliff & linearity
    /// @return tokensAvailable Amount of unlocked `baseToken` at the current time
    /// @param auctionId `auctionId` of the auction bid on
    /// @param baseAmount Amount of total vested `baseToken`
    function tokensAvailableForWithdrawal(uint256 auctionId, uint128 baseAmount)
        public
        view
        returns (uint128 tokensAvailable)
    {
        Auction storage a = idToAuction[auctionId];
        return CommonTokenMath.tokensAvailableAtTime(
            a.timings.vestingStartTimestamp,
            a.timings.vestingEndTimestamp,
            uint32(block.timestamp),
            a.timings.cliffPercent,
            baseAmount
        );
    }

    function computeCommitment(bytes32 message) public pure returns (bytes32) {
        return keccak256(abi.encode(message));
    }

    function computeMessage(uint128 baseAmount, bytes16 salt) external pure returns (bytes32) {
        return bytes32(abi.encodePacked(baseAmount, salt));
    }

    function getTimings(uint256 auctionId) external view returns (Timings memory) {
        return idToAuction[auctionId].timings;
    }

    function getAuctionData(uint256 auctionId) external view returns (AuctionData memory) {
        return idToAuction[auctionId].data;
    }

    function getBid(uint256 auctionId, uint256 bidIndex) external view returns (EncryptedBid memory) {
        return idToAuction[auctionId].bids[bidIndex];
    }
}
        

/FixedPointMathLib.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant MAX_UINT256 = 2**256 - 1;

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // Divide x * y by the denominator.
            z := div(mul(x, y), denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // If x * y modulo the denominator is strictly greater than 0,
            // 1 is added to round up the division of x * y by the denominator.
            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            // Goal was to get z*z*y within a small factor of x. More iterations could
            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
            // We ensured y >= 256 so that the relative difference between y and y+1 is small.
            // That's not possible if x < 256 but we can just verify those cases exhaustively.

            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.

            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.

            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.

            // There is no overflow risk here since y < 2^136 after the first branch above.
            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Mod x by y. Note this will return
            // 0 instead of reverting if y is zero.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // Divide x by y. Note this will return
            // 0 instead of reverting if y is zero.
            r := div(x, y)
        }
    }

    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Add 1 to x * y if x % y > 0. Note this will
            // return 0 instead of reverting if y is zero.
            z := add(gt(mod(x, y), 0), div(x, y))
        }
    }
}
          

/SafeTransferLib.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
            mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}
          

/MerkleProofLib.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Gas optimized merkle proof verification library.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from Solady (https://github.com/Vectorized/solady/blob/main/src/utils/MerkleProofLib.sol)
library MerkleProofLib {
    function verify(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool isValid) {
        /// @solidity memory-safe-assembly
        assembly {
            if proof.length {
                // Left shifting by 5 is like multiplying by 32.
                let end := add(proof.offset, shl(5, proof.length))

                // Initialize offset to the offset of the proof in calldata.
                let offset := proof.offset

                // Iterate over proof elements to compute root hash.
                // prettier-ignore
                for {} 1 {} {
                    // Slot where the leaf should be put in scratch space. If
                    // leaf > calldataload(offset): slot 32, otherwise: slot 0.
                    let leafSlot := shl(5, gt(leaf, calldataload(offset)))

                    // Store elements to hash contiguously in scratch space.
                    // The xor puts calldataload(offset) in whichever slot leaf
                    // is not occupying, so 0 if leafSlot is 32, and 32 otherwise.
                    mstore(leafSlot, leaf)
                    mstore(xor(leafSlot, 32), calldataload(offset))

                    // Reuse leaf to store the hash to reduce stack operations.
                    leaf := keccak256(0, 64) // Hash both slots of scratch space.

                    offset := add(offset, 32) // Shift 1 word per cycle.

                    // prettier-ignore
                    if iszero(lt(offset, end)) { break }
                }
            }

            isValid := eq(leaf, root) // The proof is valid if the roots match.
        }
    }
}
          

/ERC20.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

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

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}
          

/

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;

import {ECCMath} from "../util/ECCMath.sol";

interface ISizeSealed {
    ////////////////////////////////////
    ///            ERRORS            ///
    ////////////////////////////////////

    error InvalidTimestamp();
    error InvalidCliffPercent();
    error InvalidBidAmount();
    error InvalidState();
    error InvalidReserve();
    error InvalidCalldata();
    error UnauthorizedCaller();
    error CommitmentMismatch();
    error InvalidProof();
    error InvalidPrivateKey();
    error UnexpectedBalanceChange();
    error InvalidSorting();
    error TokenDoesNotExist();
    error OverfilledAuction();
    error IncorrectBidIndices();

    /////////////////////////////////////////
    ///              ENUMS                ///
    /////////////////////////////////////////

    enum States {
        Created,
        AcceptingBids,
        RevealPeriod,
        Voided,
        Finalized
    }

    /////////////////////////////////////////
    ///              STRUCTS              ///
    /////////////////////////////////////////

    struct EncryptedBid {
        address sender;
        uint128 quoteAmount;
        uint128 initialIndex;
        uint128 filledBaseAmount;
        uint128 baseWithdrawn;
        bytes32 commitment;
        ECCMath.Point pubKey;
        bytes32 encryptedMessage;
    }

    /// @param startTimestamp When the auction opens for bidding
    /// @param endTimestamp When the auction closes for bidding
    /// @param vestingStartTimestamp When linear vesting starts
    /// @param vestingEndTimestamp When linear vesting is complete
    /// @param cliffPercent Normalized percentage of base tokens to unlock at vesting start
    struct Timings {
        uint32 startTimestamp;
        uint32 endTimestamp;
        uint32 vestingStartTimestamp;
        uint32 vestingEndTimestamp;
        uint128 cliffPercent;
    }

    struct AuctionData {
        address seller;
        bool finalized;
        uint128 clearingBase;
        uint128 clearingQuote;
        uint256 privKey;
    }

    /// @param baseToken The ERC20 to be sold by the seller
    /// @param quoteToken The ERC20 to be bid by the bidders
    /// @param reserveQuotePerBase Minimum price that bids will be filled at
    /// @param totalBaseAmount Max amount of `baseToken` to be auctioned
    /// @param minimumBidQuote Minimum quote amount a bid can buy
    /// @param pubKey On-chain storage of seller's ephemeral public key
    struct AuctionParameters {
        address baseToken;
        address quoteToken;
        uint256 reserveQuotePerBase;
        uint128 totalBaseAmount;
        uint128 minimumBidQuote;
        bytes32 merkleRoot;
        ECCMath.Point pubKey;
    }

    struct Auction {
        Timings timings;
        AuctionData data;
        AuctionParameters params;
        EncryptedBid[] bids;
    }

    ////////////////////////////////////
    ///            EVENTS            ///
    ////////////////////////////////////

    event AuctionCreated(
        uint256 auctionId, address seller, AuctionParameters params, Timings timings, bytes encryptedPrivKey
    );

    event AuctionCanceled(uint256 auctionId);

    event Bid(
        address sender,
        uint256 auctionId,
        uint256 bidIndex,
        uint128 quoteAmount,
        bytes32 commitment,
        ECCMath.Point pubKey,
        bytes32 encryptedMessage,
        bytes encryptedPrivateKey
    );

    event BidCanceled(uint256 auctionId, uint256 bidIndex);

    event BiddingStopped(uint256 auctionId);

    event RevealedKey(uint256 auctionId, uint256 privateKey);

    event AuctionFinalized(uint256 auctionId, uint256[] bidIndices, uint256 filledBase, uint256 filledQuote);

    event BidRefund(uint256 auctionId, uint256 bidIndex);

    event Withdrawal(uint256 auctionId, uint256 bidIndex, uint256 withdrawAmount, uint256 remainingAmount);
}
          

/

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;

import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";

library CommonTokenMath {
    /*//////////////////////////////////////////////////////////////
                                VESTING
    //////////////////////////////////////////////////////////////*/

    //                endTimestamp      vestingStart            vestingEnd
    //        ┌─────────────┬─────────────────┬──────────────────────────────┐
    //        │                                                     │        │
    //        │             │                 │                              │
    //        │                                                     │        │
    //        │             │                 │                     ▽        │
    //        │                                                   ┌── ◁─ ─ ─ ┤totalBaseAmount
    //        │             │                 │                 ┌─┘          │
    //        │                                               ┌─┘            │
    //        │             │                 │             ┌─┘              │
    //        │                                           ┌─┘                │
    //                      │                 │         ┌─┘                  │
    //    Unlocked                                    ┌─┘                    │
    //     Tokens           │                 │     ┌─┘                      │
    //                                            ┌─┘                        │
    //        │             │                 ▽ ┌─┘                          │
    //        │                               ┌─┘◁─ ─ ─ ─ ─ ┐                │
    //        │             │                 │             │                │
    //        │                               │             │                │
    //        │             │                 │        cliffPercent          │
    //        │                               │             │                │
    //        │             │                 │             │                │
    //        │             ▽                 │             │                │
    //        │             ──────────────────┘  ◁─ ─ ─ ─ ─ ┘                │
    //        │                                                              │
    //        └────────────────────────────  Time  ──────────────────────────┘
    //

    /// @dev Helper function to determine tokens at a specific `block.timestamp`
    /// @return tokensAvailable Amount of unlocked `baseToken` at the current `block.timestamp`
    /// @param vestingStart Start of linear vesting
    /// @param vestingEnd Completion of linear vesting
    /// @param currentTime Timestamp to evaluate at
    /// @param cliffPercent Normalized percent to unlock at vesting start
    /// @param baseAmount Total amount of vested `baseToken`
    function tokensAvailableAtTime(
        uint32 vestingStart,
        uint32 vestingEnd,
        uint32 currentTime,
        uint128 cliffPercent,
        uint128 baseAmount
    ) internal pure returns (uint128) {
        if (currentTime > vestingEnd) {
            return baseAmount; // If vesting is over, bidder is owed all tokens
        } else if (currentTime <= vestingStart) {
            return 0; // If cliff hasn't been triggered yet, bidder receives no tokens
        } else {
            // Vesting is active and cliff has triggered
            uint256 cliffAmount = FixedPointMathLib.mulDivDown(baseAmount, cliffPercent, 1e18);

            return uint128(
                cliffAmount
                    + FixedPointMathLib.mulDivDown(
                        baseAmount - cliffAmount, currentTime - vestingStart, vestingEnd - vestingStart
                    )
            );
        }
    }
}
          

/

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;

library ECCMath {
    // https://eips.ethereum.org/EIPS/eip-197#definition-of-the-groups
    uint256 internal constant GX = 1;
    uint256 internal constant GY = 2;

    struct Point {
        uint256 x;
        uint256 y;
    }

    /// @notice Returns the corresponding public key of the private key
    /// @dev Calculates G*k
    function publicKey(uint256 privateKey) internal view returns (Point memory) {
        return ecMul(Point(GX, GY), privateKey);
    }

    /// @notice Calculates elliptic curve scalar multiplication (point * scalar)
    /// @dev Returns (1,1) if the ecMul failed or invalid parameters
    function ecMul(Point memory point, uint256 scalar) internal view returns (Point memory) {
        if (scalar == 0 || (point.x == 0 && point.y == 0)) return Point(1, 1);
        (bool res, bytes memory ret) = address(0x07).staticcall{gas: 6000}(abi.encode(point, scalar));
        if (!res) return Point(1, 1);
        return abi.decode(ret, (Point));
    }

    /// @dev After encryption, both the seller and buyer private keys can decrypt
    /// @param encryptToPub public key to which the message gets encrypted
    /// @param encryptWithPriv private key to use for encryption
    /// @param message arbitrary 32 bytes
    function encryptMessage(Point memory encryptToPub, uint256 encryptWithPriv, bytes32 message)
        internal
        view
        returns (Point memory buyerPub, bytes32 encryptedMessage)
    {
        Point memory sharedPoint = ecMul(encryptToPub, encryptWithPriv);
        bytes32 sharedKey = hashPoint(sharedPoint);
        encryptedMessage = message ^ sharedKey;
        buyerPub = publicKey(encryptWithPriv);
    }

    /// @notice Decrypts a message that was encrypted using `encryptMessage()`
    /// @param sharedPoint (G*k1)*k2 where k1 and k2 are the
    ///      private keys of the two parties that can decrypt
    function decryptMessage(Point memory sharedPoint, bytes32 encryptedMessage)
        internal
        pure
        returns (bytes32 decryptedMessage)
    {
        return encryptedMessage ^ hashPoint(sharedPoint);
    }

    function hashPoint(Point memory point) internal pure returns (bytes32) {
        return keccak256(abi.encode(point));
    }
}
          

Compiler Settings

{"viaIR":true,"remappings":[":ds-test/=lib/solmate/lib/ds-test/src/",":forge-std/=lib/forge-std/src/",":murky/=lib/murky/src/",":openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/",":solmate/=lib/solmate/src/"],"optimizer":{"runs":1000000,"enabled":true},"metadata":{"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"london","compilationTarget":{"src/SizeSealed.sol":"SizeSealed"}}
              

Contract ABI

[{"type":"error","name":"CommitmentMismatch","inputs":[]},{"type":"error","name":"IncorrectBidIndices","inputs":[]},{"type":"error","name":"InvalidBidAmount","inputs":[]},{"type":"error","name":"InvalidCalldata","inputs":[]},{"type":"error","name":"InvalidCliffPercent","inputs":[]},{"type":"error","name":"InvalidPrivateKey","inputs":[]},{"type":"error","name":"InvalidProof","inputs":[]},{"type":"error","name":"InvalidReserve","inputs":[]},{"type":"error","name":"InvalidSorting","inputs":[]},{"type":"error","name":"InvalidState","inputs":[]},{"type":"error","name":"InvalidTimestamp","inputs":[]},{"type":"error","name":"OverfilledAuction","inputs":[]},{"type":"error","name":"TokenDoesNotExist","inputs":[]},{"type":"error","name":"UnauthorizedCaller","inputs":[]},{"type":"error","name":"UnexpectedBalanceChange","inputs":[]},{"type":"event","name":"AuctionCanceled","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AuctionCreated","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":false},{"type":"address","name":"seller","internalType":"address","indexed":false},{"type":"tuple","name":"params","internalType":"struct ISizeSealed.AuctionParameters","indexed":false,"components":[{"type":"address","name":"baseToken","internalType":"address"},{"type":"address","name":"quoteToken","internalType":"address"},{"type":"uint256","name":"reserveQuotePerBase","internalType":"uint256"},{"type":"uint128","name":"totalBaseAmount","internalType":"uint128"},{"type":"uint128","name":"minimumBidQuote","internalType":"uint128"},{"type":"bytes32","name":"merkleRoot","internalType":"bytes32"},{"type":"tuple","name":"pubKey","internalType":"struct ECCMath.Point","components":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]}]},{"type":"tuple","name":"timings","internalType":"struct ISizeSealed.Timings","indexed":false,"components":[{"type":"uint32","name":"startTimestamp","internalType":"uint32"},{"type":"uint32","name":"endTimestamp","internalType":"uint32"},{"type":"uint32","name":"vestingStartTimestamp","internalType":"uint32"},{"type":"uint32","name":"vestingEndTimestamp","internalType":"uint32"},{"type":"uint128","name":"cliffPercent","internalType":"uint128"}]},{"type":"bytes","name":"encryptedPrivKey","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"AuctionFinalized","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":false},{"type":"uint256[]","name":"bidIndices","internalType":"uint256[]","indexed":false},{"type":"uint256","name":"filledBase","internalType":"uint256","indexed":false},{"type":"uint256","name":"filledQuote","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Bid","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":false},{"type":"uint256","name":"bidIndex","internalType":"uint256","indexed":false},{"type":"uint128","name":"quoteAmount","internalType":"uint128","indexed":false},{"type":"bytes32","name":"commitment","internalType":"bytes32","indexed":false},{"type":"tuple","name":"pubKey","internalType":"struct ECCMath.Point","indexed":false,"components":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"bytes32","name":"encryptedMessage","internalType":"bytes32","indexed":false},{"type":"bytes","name":"encryptedPrivateKey","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"BidCanceled","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":false},{"type":"uint256","name":"bidIndex","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BidRefund","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":false},{"type":"uint256","name":"bidIndex","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BiddingStopped","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RevealedKey","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":false},{"type":"uint256","name":"privateKey","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Withdrawal","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":false},{"type":"uint256","name":"bidIndex","internalType":"uint256","indexed":false},{"type":"uint256","name":"withdrawAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"remainingAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"bid","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"},{"type":"uint128","name":"quoteAmount","internalType":"uint128"},{"type":"bytes32","name":"commitment","internalType":"bytes32"},{"type":"tuple","name":"pubKey","internalType":"struct ECCMath.Point","components":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"bytes32","name":"encryptedMessage","internalType":"bytes32"},{"type":"bytes","name":"encryptedPrivateKey","internalType":"bytes"},{"type":"bytes32[]","name":"proof","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelAuction","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelBid","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"},{"type":"uint256","name":"bidIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"computeCommitment","inputs":[{"type":"bytes32","name":"message","internalType":"bytes32"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"computeMessage","inputs":[{"type":"uint128","name":"baseAmount","internalType":"uint128"},{"type":"bytes16","name":"salt","internalType":"bytes16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"createAuction","inputs":[{"type":"tuple","name":"auctionParams","internalType":"struct ISizeSealed.AuctionParameters","components":[{"type":"address","name":"baseToken","internalType":"address"},{"type":"address","name":"quoteToken","internalType":"address"},{"type":"uint256","name":"reserveQuotePerBase","internalType":"uint256"},{"type":"uint128","name":"totalBaseAmount","internalType":"uint128"},{"type":"uint128","name":"minimumBidQuote","internalType":"uint128"},{"type":"bytes32","name":"merkleRoot","internalType":"bytes32"},{"type":"tuple","name":"pubKey","internalType":"struct ECCMath.Point","components":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]}]},{"type":"tuple","name":"timings","internalType":"struct ISizeSealed.Timings","components":[{"type":"uint32","name":"startTimestamp","internalType":"uint32"},{"type":"uint32","name":"endTimestamp","internalType":"uint32"},{"type":"uint32","name":"vestingStartTimestamp","internalType":"uint32"},{"type":"uint32","name":"vestingEndTimestamp","internalType":"uint32"},{"type":"uint128","name":"cliffPercent","internalType":"uint128"}]},{"type":"bytes","name":"encryptedSellerPrivKey","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"currentAuctionId","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"finalize","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"},{"type":"uint256[]","name":"bidIndices","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct ISizeSealed.AuctionData","components":[{"type":"address","name":"seller","internalType":"address"},{"type":"bool","name":"finalized","internalType":"bool"},{"type":"uint128","name":"clearingBase","internalType":"uint128"},{"type":"uint128","name":"clearingQuote","internalType":"uint128"},{"type":"uint256","name":"privKey","internalType":"uint256"}]}],"name":"getAuctionData","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct ISizeSealed.EncryptedBid","components":[{"type":"address","name":"sender","internalType":"address"},{"type":"uint128","name":"quoteAmount","internalType":"uint128"},{"type":"uint128","name":"initialIndex","internalType":"uint128"},{"type":"uint128","name":"filledBaseAmount","internalType":"uint128"},{"type":"uint128","name":"baseWithdrawn","internalType":"uint128"},{"type":"bytes32","name":"commitment","internalType":"bytes32"},{"type":"tuple","name":"pubKey","internalType":"struct ECCMath.Point","components":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"bytes32","name":"encryptedMessage","internalType":"bytes32"}]}],"name":"getBid","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"},{"type":"uint256","name":"bidIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct ISizeSealed.Timings","components":[{"type":"uint32","name":"startTimestamp","internalType":"uint32"},{"type":"uint32","name":"endTimestamp","internalType":"uint32"},{"type":"uint32","name":"vestingStartTimestamp","internalType":"uint32"},{"type":"uint32","name":"vestingEndTimestamp","internalType":"uint32"},{"type":"uint128","name":"cliffPercent","internalType":"uint128"}]}],"name":"getTimings","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"timings","internalType":"struct ISizeSealed.Timings","components":[{"type":"uint32","name":"startTimestamp","internalType":"uint32"},{"type":"uint32","name":"endTimestamp","internalType":"uint32"},{"type":"uint32","name":"vestingStartTimestamp","internalType":"uint32"},{"type":"uint32","name":"vestingEndTimestamp","internalType":"uint32"},{"type":"uint128","name":"cliffPercent","internalType":"uint128"}]},{"type":"tuple","name":"data","internalType":"struct ISizeSealed.AuctionData","components":[{"type":"address","name":"seller","internalType":"address"},{"type":"bool","name":"finalized","internalType":"bool"},{"type":"uint128","name":"clearingBase","internalType":"uint128"},{"type":"uint128","name":"clearingQuote","internalType":"uint128"},{"type":"uint256","name":"privKey","internalType":"uint256"}]},{"type":"tuple","name":"params","internalType":"struct ISizeSealed.AuctionParameters","components":[{"type":"address","name":"baseToken","internalType":"address"},{"type":"address","name":"quoteToken","internalType":"address"},{"type":"uint256","name":"reserveQuotePerBase","internalType":"uint256"},{"type":"uint128","name":"totalBaseAmount","internalType":"uint128"},{"type":"uint128","name":"minimumBidQuote","internalType":"uint128"},{"type":"bytes32","name":"merkleRoot","internalType":"bytes32"},{"type":"tuple","name":"pubKey","internalType":"struct ECCMath.Point","components":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]}]}],"name":"idToAuction","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"refund","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"},{"type":"uint256","name":"bidIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"reveal","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"},{"type":"uint256","name":"privateKey","internalType":"uint256"},{"type":"uint256[]","name":"finalizeBidIndices","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"tokensAvailable","internalType":"uint128"}],"name":"tokensAvailableForWithdrawal","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"},{"type":"uint128","name":"baseAmount","internalType":"uint128"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"},{"type":"uint256","name":"bidIndex","internalType":"uint256"}]}]
              

Contract Creation Code

0x6080806040523461001657613773908161001c8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c806301f5274114612563578063089bc2a114612483578063089dc92c1461228d5780630c0b86ca146122515780631c776d4b14611d9257806337c0d67a14611d34578063441a3e7014611a4b57806344f27e30146119955780634b3936051461165e5780634fd1b36414610c15578063582c7ffd14610aff5780635af36e3e1461091d57806396b5a755146107ad5780639f57665d14610706578063aed6f1fb146101155763c387742b146100cc57600080fd5b346101105760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576020610108600435613499565b604051908152f35b600080fd5b34610110577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36016101c0811261011057610100136101105760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefc360112610110576101a43567ffffffffffffffff811161011057610199903690600401612d86565b906101a2612e19565b63ffffffff42911611156106dc576101b8612e2d565b63ffffffff806101c6612e19565b16911610156106dc576101d7612e19565b63ffffffff806101e5612e41565b169116116106dc576101f5612e41565b63ffffffff80610203612e55565b169116116106dc57670de0b6b3a76400006fffffffffffffffffffffffffffffffff61022d612e69565b16116106b25761026061023e612e89565b6fffffffffffffffffffffffffffffffff80610258612ea8565b169116612f79565b6044351061068857610270612ec7565b3b158015610678575b61064e57610288600054612f0d565b9081600055816000526001602052604060002061046a6fffffffff00000000000000000000000063ffffffff6102bc612e2d565b1683549067ffffffff000000006102d1612e19565b60201b166bffffffff00000000000000006102ea612e41565b60401b16916102f7612e55565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000095869160601b169416171717178355610373610332612e69565b84546fffffffffffffffffffffffffffffffff1660809190911b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016178455565b600183017fffffffffffffffffffffffff00000000000000000000000000000000000000009033828254161790556004840173ffffffffffffffffffffffffffffffffffffffff6103c2612eea565b1682825416179055600584019073ffffffffffffffffffffffffffffffffffffffff6103ec612ec7565b1690825416179055604435600684015560078301906fffffffffffffffffffffffffffffffff61041a612ea8565b169082541617815561042a612e89565b6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b60a435600882015560c4356009820155600a60e4359101556104af61048d612eea565b6fffffffffffffffffffffffffffffffff6104a6612ea8565b16903390612fef565b60405182815233602082015260043573ffffffffffffffffffffffffffffffffffffffff811681036101105773ffffffffffffffffffffffffffffffffffffffff16604082015260243573ffffffffffffffffffffffffffffffffffffffff811680910361011057606082015260443560808201526064356fffffffffffffffffffffffffffffffff81168091036101105760a08201526084356fffffffffffffffffffffffffffffffff81168091036101105760c082015260a43560e082015260c43561010082015260e4356101208201526101043563ffffffff8116809103610110576101408201526101243563ffffffff8116809103610110576101608201526101443563ffffffff8116809103610110576101808201526101643563ffffffff8116809103610110576101a082015261018435936fffffffffffffffffffffffffffffffff8516809503610110576106437f31c830bc1416d065437dc163658a4eadf13b34e66aec1dddbb38fa05e83d7bf79383926020976101c0850152610200806101e0860152840191612f3a565b0390a1604051908152f35b60046040517fceea21b6000000000000000000000000000000000000000000000000000000008152fd5b50610681612eea565b3b15610279565b60046040517fe46aea09000000000000000000000000000000000000000000000000000000008152fd5b60046040517f31fa14c6000000000000000000000000000000000000000000000000000000008152fd5b60046040517fb7d09497000000000000000000000000000000000000000000000000000000008152fd5b346101105760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101105761073d6134b6565b50600435600052600160205260a06107586040600020612cbf565b6107ab60405180926fffffffffffffffffffffffffffffffff6080809263ffffffff8082511686528060208301511660208701528060408301511660408701526060820151166060860152015116910152565bf35b346101105760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576004358060005260016020526040600020600181019182549073ffffffffffffffffffffffffffffffffffffffff80831633036108f35760ff8360a01c166108c9577f28601d865dccc9f113e15a7185c1b38c085d598c71250d3337916a428536d77160206007936108c7977fffffffffffffffffffffffff00000000000000000000000000000000000000006fffffffffffffffffffffffffffffffff9716905567ffffffff000000007fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff885416178755604051908152a1600484015416920154169033906132ce565b005b60046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5c427cd9000000000000000000000000000000000000000000000000000000008152fd5b346101105761092b36612de5565b90806000526001602052604060002080549063ffffffff9182811642106000146109795760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60201c821690428211156109b15760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b6001015460a01c60ff1615610a8957505080600052600160205260406000206109dd83600b830161324f565b509182549073ffffffffffffffffffffffffffffffffffffffff9081831633036108f3576fffffffffffffffffffffffffffffffff93846002870154166108c9577f2734c8894183ae15778d25f03eb03cddaf925d0ee834245c1e03a328a89aeb7060406005936108c7997fffffffffffffffffffffffff0000000000000000000000000000000000000000600198168a5582519182526020820152a1015416920154169033906132ce565b81610a93826131e6565b164211610ac45760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b610acd906131e6565b164211156101105760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b34610110576101206020610b33610b1536612de5565b90610b1e6131fd565b5060005260018352600b60406000200161324f565b506040519182808093610b4582612ba4565b73ffffffffffffffffffffffffffffffffffffffff808254168352600182015491858401906fffffffffffffffffffffffffffffffff8481809694818096168152604089019260801c835260028501549660e0600660608c0197858b16895260808d019a60801c8b5260a060038201549d019c8d5260c0610bc860048301612d68565b9e019d8e5201549d019c8d526040519d51168d525116898c0152511660408a015251166060880152511660808601525160a085015251805160c0850152015160e083015251610100820152f35b346101105760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101105760243560443567ffffffffffffffff811161011057610c67903690600401612db4565b90600435600052600160205260406000209283549363ffffffff948581164210600014610cb85760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60201c85169042821115610cf05760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b6001015460a01c60ff1615610d295760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b84610d33826131e6565b164211611654575060043560005260016020526040600020600381019081546108c95760006020604051610d6681612b88565b8281520152610d8b83604051610d7b81612b88565b60018152600260208201526135b8565b8051600983015481149283159361163f575b50821561161d575b50506115f357817f636dccec5dc3756424ee9e96168463de735c92a85fb2642812ea6e0b2bd61763926040925581519060043582526020820152a181610de757005b610df2913691612c52565b906004356000526001602052604060002080548281164210600014610e3b5760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60201c82169042821115610e735760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b6001015460a01c60ff1615610eac5760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b81610eb6826131e6565b164211610ac45750506004356000526001602052604060002090600382015480156115f3578151600b840154036115c95760405190610ef482612b6c565b60006040830152600060a0830152600684015482526fffffffffffffffffffffffffffffffff60078501541660208301526fffffffffffffffffffffffffffffffff606083015260016080830152825160081c9060018201821161159a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610f9a6001610f83818601612c3a565b94610f916040519687612bf9565b01808552612c3a565b0136602084013760005b845181101561123757610fb781866132a7565b5190610fc682600b890161324f565b5091610fd58160081c866132a7565b51600160ff83161b8082161461120d57610ffb90600160ff84161b179160081c866132a7565b526110118361100c60048501612d68565b6135b8565b805160018114806111ff575b6111e857600684015491602060405191818301938452015160408201526040815261104781612bdd565b5190201861105481613499565b6003840154036111f45760801c60018301549080156111e85761108d60808801516fffffffffffffffffffffffffffffffff84166132bb565b61109b8260608a01516132bb565b90818110156111a2575b5050611171936110c7826fffffffffffffffffffffffffffffffff8516612f79565b88511161119a5760a088015160208901518114611191578261111291611167958260808d01526fffffffffffffffffffffffffffffffff811660608d015260801c60408c015261329a565b6020890151809111611176575b506002016fffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffffffffffff0000000000000000000000000000000082541617905560a087015161329a565b60a0860152612f0d565b610fa4565b600291925061118a9060a08a015190612fe2565b919061111f565b50505050612f0d565b505050612f0d565b036111be578160801c6040880151116111be576111718a6110a5565b60046040517fca428236000000000000000000000000000000000000000000000000000000008152fd5b50506111719150612f0d565b506111719150612f0d565b50600160208301511461101d565b60046040517f063c8ab3000000000000000000000000000000000000000000000000000000008152fd5b505090916fffffffffffffffffffffffffffffffff60608401511661129c600286019182906fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b6fffffffffffffffffffffffffffffffff6080850151167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055600184015493740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff861617600182015560005b83517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081810190811161159a578210156113755761136182866132a7565b510361120d5761137090612f0d565b611322565b505092909391805190817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81011161159a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6113d39201906132a7565b51600160ff8651161b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820191821161159a570361120d5760a08101516020820151106115705760a09160208201519083830151918281116114f3575b50505061147861144e606083015184840151608085015191612fae565b809473ffffffffffffffffffffffffffffffffffffffff60018160058401541692015416906133a1565b01519060405191608083016004358452608060208501528451809152602060a0850195019060005b8181106114dd57505050604083015260608201527f59910662e012236ad53bd4a7844ec083eb64c4477c85386182b5b503eeedbb339181900390a1005b82518752602096870196909201916001016114a0565b6115689261150091612fe2565b906fffffffffffffffffffffffffffffffff85850151167fffffffffffffffffffffffffffffffff0000000000000000000000000000000060078801541617600787015573ffffffffffffffffffffffffffffffffffffffff806004880154169116906133a1565b848080611431565b60046040517fac59a90a000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60046040517f8129bbcd000000000000000000000000000000000000000000000000000000008152fd5b60046040517fea63ebbc000000000000000000000000000000000000000000000000000000008152fd5b600114915081611630575b508680610da5565b60019150602001511486611628565b6020830151600a909101541415925088610d9d565b610acd85916131e6565b346101105761166c36612de5565b908060005260019081602052604060002090600b82019361168d818661324f565b5073ffffffffffffffffffffffffffffffffffffffff928382541633036108f357859163ffffffff80875460201c16908142101561195b575b50506fffffffffffffffffffffffffffffffff968791015416958754907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9182810190811161159a57611719908a61324f565b50611724868b61324f565b9290926117b757818303611815575b505050875480156117e657019261174a848961324f565b9490946117b7576108c798600060068782604098817f2a0a5f509bc9b1f09c4172bec62e98d404d2f98b3977aa9b9a2bb243671f5fe29b5582015582600282015582600382015582600482015582600582015501555582519182526020820152a1600533920154166132ce565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b8161191e600693928a859454167fffffffffffffffffffffffff0000000000000000000000000000000000000000875416178655888601906118c68a85019282845416937fffffffffffffffffffffffffffffffff0000000000000000000000000000000094858354161782555460801c6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b60028701916002850191825416908354161782555460801c6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b600381015460038501556004840160048201808203611947575b50500154910155888080611733565b549055600581015460058501558c80611938565b90919360ff9088015460a01c1691821561197f575b50506108c957859188806116c6565b61198a9192506131e6565b164211158880611970565b346101105760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576119cc6134b6565b50600435600052600160205260a06119ea6001604060002001612d02565b6107ab60405180926080809173ffffffffffffffffffffffffffffffffffffffff81511684526020810151151560208501526fffffffffffffffffffffffffffffffff80604083015116604086015260608201511660608501520151910152565b3461011057611a5936612de5565b90806000526001602052604060002080549063ffffffff918281164210600014611aa75760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60201c82169042821115611adf5760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b6001015460a01c60ff1615610a89575050806000526001602052604060002091611b0c81600b850161324f565b509073ffffffffffffffffffffffffffffffffffffffff918281541633036108f35760028101908154916fffffffffffffffffffffffffffffffff948584169283156108c95786611b6b611b60868b613465565b9660801c809761337f565b168095019087821161159a57611bbf60019285906fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b0180549087821680611c2f575b507ff8daa50652e9e7fc7e0021bea02c37ee39e453b5580c070fd3ca257a166939b360808a8a8a8a8f8b8b611c0c84611c15948e600433920154166133a1565b54871c9061337f565b9160405194855260208501526040840152166060820152a1005b90939198979695949260028b01549a888c60801c9c16918c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0486118d0215830215610110577ff8daa50652e9e7fc7e0021bea02c37ee39e453b5580c070fd3ca257a166939b39c60809c611c1598611c0c968b96611cf8948b0281810615159190040190818110611d09577fffffffffffffffffffffffffffffffff0000000000000000000000000000000091611ce691612fe2565b925b16905533836005860154166133a1565b94969798999a509a50829450611bcc565b50507fffffffffffffffffffffffffffffffff00000000000000000000000000000000600092611ce8565b346101105760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576020611d78611d70612ca0565b600435613465565b6fffffffffffffffffffffffffffffffff60405191168152f35b34610110576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011057611dca612ca0565b60407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c3601126101105767ffffffffffffffff9060c43582811161011057611e16903690600401612d86565b9260e43590811161011057611e2f903690600401612db4565b906004356000526001602052604060002080549063ffffffff918281164210600014611e7f5760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b829060201c16908142101561221857505050600435600052600160205260406000209160088301549182612185575b50505073ffffffffffffffffffffffffffffffffffffffff60018201541633146108f3576fffffffffffffffffffffffffffffffff8316158015612163575b61213957600b810154926103e88410156108c957611f096131fd565b923384526fffffffffffffffffffffffffffffffff821660208501526fffffffffffffffffffffffffffffffff8516604085015260443560a0850152604051611f5181612b88565b6064358152608435602082015260c085015260a43560e08501526801000000000000000085101561210a5760018501600b840155611f9285600b850161324f565b9190916117b757845182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020808601516040870151608090811b7fffffffffffffffffffffffffffffffff000000000000000000000000000000009081166fffffffffffffffffffffffffffffffff9384161760018701556060890151828a0151908416921b1617600285015590977f6240129d8b257ecc07022e0f251b3e713a516f8b1e53a125b6ac0271f6aa621c9691956106439491926120bc929060069060e09060a081015160038501558d60c0820151805160048701550151600585015501519101558686169073ffffffffffffffffffffffffffffffffffffffff60053392015416612fef565b6040519485943386526004358a870152886040870152166060850152604435608085015260643560a085015260843560c085015260a43560e085015261012080610100860152840191612f3a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60046040517fe83664ea000000000000000000000000000000000000000000000000000000008152fd5b50600781015460801c6fffffffffffffffffffffffffffffffff841610611eed565b819060405160208101903360601b8252601481526121a281612b88565b519020926121e4575b5050036121ba57848080611eae565b60046040517f09bde339000000000000000000000000000000000000000000000000000000008152fd5b80925b602084359182811160051b9081521852602060406000209301928260051b820184106121e7579250505086806121ab565b6001015460a01c60ff1615610a895760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b346101105760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576020600054604051908152f35b346101105760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011057600435600052600160205260406000206122d581612cbf565b906122e260018201612d02565b9060405160e0810181811067ffffffffffffffff82111761210a5760405273ffffffffffffffffffffffffffffffffffffffff90816004840154168152816005840154169060208101918252600684015491604082019283526007850154928460608401926fffffffffffffffffffffffffffffffff9687958688168652608081019760801c885260088a01549960a082019a8b5260090161238390612d68565b9a60c082019b8c526040519c8d6123df916fffffffffffffffffffffffffffffffff6080809263ffffffff8082511686528060208301511660208701528060408301511660408701526060820151166060860152015116910152565b805173ffffffffffffffffffffffffffffffffffffffff1660a08e01526020810151151560c08e015260408101516fffffffffffffffffffffffffffffffff90811660e08f01526060820151166101008e0152608001516101208d015251166101408b015251166101608901525161018088015251166101a086015251166101c0840152516101e08301525180516102008301526020015161022082015261024090f35b346101105760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576004356fffffffffffffffffffffffffffffffff8116810361011057602435907fffffffffffffffffffffffffffffffff0000000000000000000000000000000080831680930361011057602092604051918483019360801b168352603082015282815261251f81612b88565b51905190828110612534575b50604051908152f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90830360031b1b168261252b565b346101105760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101105760243567ffffffffffffffff81116101105736602382011215610110576125c3903690602481600401359101612c52565b6004356000526001602052604060002080549063ffffffff9182811642106000146126125760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60201c8216904282111561264a5760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b6001015460a01c60ff16156126835760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b8161268d826131e6565b164211610ac457826004356000526001602052604060002090600382015480156115f3578151600b840154036115c957604051906126ca82612b6c565b60006040830152600060a0830152600684015482526fffffffffffffffffffffffffffffffff60078501541660208301526fffffffffffffffffffffffffffffffff606083015260016080830152825160081c9060018201821161159a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06127596001610f83818601612c3a565b0136602084013760005b84518110156128c75761277681866132a7565b519061278582600b890161324f565b50916127948160081c866132a7565b51600160ff83161b8082161461120d576127ba90600160ff84161b179160081c866132a7565b526127cb8361100c60048501612d68565b805160018114806128b9575b6128a257600684015491602060405191818301938452015160408201526040815261280181612bdd565b5190201861280e81613499565b6003840154036128ae5760801c60018301549080156128a25761284760808801516fffffffffffffffffffffffffffffffff84166132bb565b6128558260608a01516132bb565b9081811015612886575b5050612881936110c7826fffffffffffffffffffffffffffffffff8516612f79565b612763565b036111be578160801c6040880151116111be576128818a61285f565b50506128819150612f0d565b506128819150612f0d565b5060016020830151146127d7565b505090916fffffffffffffffffffffffffffffffff60608401511661292c600286019182906fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b6fffffffffffffffffffffffffffffffff6080850151167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055600184015493740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff861617600182015560005b83517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081810190811161159a57821015612a05576129f182866132a7565b510361120d57612a0090612f0d565b6129b2565b5050848484805190817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81011161159a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612a629201906132a7565b51600160ff8651161b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820191821161159a570361120d5760a08101516020820151106115705760a0916020820151908383015191828111612b57575b505050612add61144e606083015184840151608085015191612fae565b01519060405191608083016004358452608060208501528451809152602060a0850195019060005b818110612b41577f59910662e012236ad53bd4a7844ec083eb64c4477c85386182b5b503eeedbb338680898888604084015260608301520390a1005b8251875260209687019690920191600101612b05565b612b649261150091612fe2565b848080612ac0565b60c0810190811067ffffffffffffffff82111761210a57604052565b6040810190811067ffffffffffffffff82111761210a57604052565b610100810190811067ffffffffffffffff82111761210a57604052565b60a0810190811067ffffffffffffffff82111761210a57604052565b6060810190811067ffffffffffffffff82111761210a57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761210a57604052565b67ffffffffffffffff811161210a5760051b60200190565b9291612c5d82612c3a565b91612c6b6040519384612bf9565b829481845260208094019160051b810192831161011057905b828210612c915750505050565b81358152908301908301612c84565b602435906fffffffffffffffffffffffffffffffff8216820361011057565b90604051612ccc81612bc1565b608081935463ffffffff8082168452808260201c166020850152808260401c1660408501528160601c166060840152811c910152565b90604051612d0f81612bc1565b60806002829460ff815473ffffffffffffffffffffffffffffffffffffffff8116865260a01c161515602085015260018101546fffffffffffffffffffffffffffffffff81166040860152831c60608501520154910152565b90604051612d7581612b88565b602060018294805484520154910152565b9181601f840112156101105782359167ffffffffffffffff8311610110576020838186019501011161011057565b9181601f840112156101105782359167ffffffffffffffff8311610110576020808501948460051b01011161011057565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040910112610110576004359060243590565b6101243563ffffffff811681036101105790565b6101043563ffffffff811681036101105790565b6101443563ffffffff811681036101105790565b6101643563ffffffff811681036101105790565b610184356fffffffffffffffffffffffffffffffff811681036101105790565b6084356fffffffffffffffffffffffffffffffff811681036101105790565b6064356fffffffffffffffffffffffffffffffff811681036101105790565b60243573ffffffffffffffffffffffffffffffffffffffff811681036101105790565b60043573ffffffffffffffffffffffffffffffffffffffff811681036101105790565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461159a5760010190565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b6fffffffffffffffffffffffffffffffff90700100000000000000000000000000000001811182021583021561011057020490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04811182021583021561011057020490565b9190820391821161159a57565b73ffffffffffffffffffffffffffffffffffffffff9092919216916040928351907f70a08231000000000000000000000000000000000000000000000000000000008083523060048401526020938484602481865afa9384156131db579085916000956131a8575b5060646000918951907f23b872dd000000000000000000000000000000000000000000000000000000008252600482015230602482015288604482015282865af13d15601f3d116001600051141617161561314b578390602487518094819382523060048301525afa9081156131405760009161310b575b506130da9250612fe2565b036130e25750565b600490517fad709933000000000000000000000000000000000000000000000000000000008152fd5b919282813d8311613139575b6131218183612bf9565b810103126131365750906130da9151386130cf565b80fd5b503d613117565b85513d6000823e3d90fd5b6064848751907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b9182819692963d83116131d4575b6131c08183612bf9565b810103126131365750519284906064613057565b503d6131b6565b87513d6000823e3d90fd5b906201518063ffffffff8093160191821161159a57565b6040519061320a82612ba4565b8160e06000918281528260208201528260408201528260608201528260808201528260a082015260405161323d81612b88565b83815283602082015260c08201520152565b805482101561326b576000526007602060002091020190600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190820180921161159a57565b805182101561326b5760209160051b010190565b8181029291811591840414171561159a57565b60009182604492602095604051937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af13d15601f3d116001600051141617161561332157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b6fffffffffffffffffffffffffffffffff918216908216039190821161159a57565b73ffffffffffffffffffffffffffffffffffffffff9092919216916040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481875afa90811561345957600091613428575b50828110613420575b50811561341b57613419926132ce565b565b505050565b915038613409565b906020823d8211613451575b8161344160209383612bf9565b8101031261313657505138613400565b3d9150613434565b6040513d6000823e3d90fd5b9061349691600052600160205260406000205463ffffffff8160801c9181421691808260601c169160401c166134f7565b90565b60405160208101918252602081526134b081612b88565b51902090565b604051906134c382612bc1565b60006080838281528260208201528260408201528260608201520152565b63ffffffff918216908216039190821161159a57565b63ffffffff93929091908481168583168111156135175750505050505090565b8386161061352a57505050505050600090565b6fffffffffffffffffffffffffffffffff80809716941694670de0b6b3a764000095807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048611810215870215610110576135a58561359f6135ae976135996135b49b87968c0204809b612fe2565b966134e1565b956134e1565b16921690612fae565b9061329a565b1690565b60408051916135c683612b88565b6000908184528160208095015284158015613728575b61371757825194848087019280518452015184870152606086015260608552608085019467ffffffffffffffff95818110878211176136ea5784525182918291906007611770fa3d156136e1573d9485116136b457825194613665857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160187612bf9565b85523d828587013e5b1561369b578184805181010312613136575080519261368c84612b88565b82810151845201519082015290565b505191506001906136ab83612b88565b81835282015290565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6060945061366e565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b50505191506001906136ab83612b88565b5080511580156135dc575083810151156135dc56fea26469706673582212200f5bf4f298a1f7b93cc1bf2d82de96f347dcea3144606d482f036217a2ba24ab64736f6c63430008130033

Deployed ByteCode

0x6080604052600436101561001257600080fd5b60003560e01c806301f5274114612563578063089bc2a114612483578063089dc92c1461228d5780630c0b86ca146122515780631c776d4b14611d9257806337c0d67a14611d34578063441a3e7014611a4b57806344f27e30146119955780634b3936051461165e5780634fd1b36414610c15578063582c7ffd14610aff5780635af36e3e1461091d57806396b5a755146107ad5780639f57665d14610706578063aed6f1fb146101155763c387742b146100cc57600080fd5b346101105760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576020610108600435613499565b604051908152f35b600080fd5b34610110577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36016101c0811261011057610100136101105760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefc360112610110576101a43567ffffffffffffffff811161011057610199903690600401612d86565b906101a2612e19565b63ffffffff42911611156106dc576101b8612e2d565b63ffffffff806101c6612e19565b16911610156106dc576101d7612e19565b63ffffffff806101e5612e41565b169116116106dc576101f5612e41565b63ffffffff80610203612e55565b169116116106dc57670de0b6b3a76400006fffffffffffffffffffffffffffffffff61022d612e69565b16116106b25761026061023e612e89565b6fffffffffffffffffffffffffffffffff80610258612ea8565b169116612f79565b6044351061068857610270612ec7565b3b158015610678575b61064e57610288600054612f0d565b9081600055816000526001602052604060002061046a6fffffffff00000000000000000000000063ffffffff6102bc612e2d565b1683549067ffffffff000000006102d1612e19565b60201b166bffffffff00000000000000006102ea612e41565b60401b16916102f7612e55565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000095869160601b169416171717178355610373610332612e69565b84546fffffffffffffffffffffffffffffffff1660809190911b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016178455565b600183017fffffffffffffffffffffffff00000000000000000000000000000000000000009033828254161790556004840173ffffffffffffffffffffffffffffffffffffffff6103c2612eea565b1682825416179055600584019073ffffffffffffffffffffffffffffffffffffffff6103ec612ec7565b1690825416179055604435600684015560078301906fffffffffffffffffffffffffffffffff61041a612ea8565b169082541617815561042a612e89565b6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b60a435600882015560c4356009820155600a60e4359101556104af61048d612eea565b6fffffffffffffffffffffffffffffffff6104a6612ea8565b16903390612fef565b60405182815233602082015260043573ffffffffffffffffffffffffffffffffffffffff811681036101105773ffffffffffffffffffffffffffffffffffffffff16604082015260243573ffffffffffffffffffffffffffffffffffffffff811680910361011057606082015260443560808201526064356fffffffffffffffffffffffffffffffff81168091036101105760a08201526084356fffffffffffffffffffffffffffffffff81168091036101105760c082015260a43560e082015260c43561010082015260e4356101208201526101043563ffffffff8116809103610110576101408201526101243563ffffffff8116809103610110576101608201526101443563ffffffff8116809103610110576101808201526101643563ffffffff8116809103610110576101a082015261018435936fffffffffffffffffffffffffffffffff8516809503610110576106437f31c830bc1416d065437dc163658a4eadf13b34e66aec1dddbb38fa05e83d7bf79383926020976101c0850152610200806101e0860152840191612f3a565b0390a1604051908152f35b60046040517fceea21b6000000000000000000000000000000000000000000000000000000008152fd5b50610681612eea565b3b15610279565b60046040517fe46aea09000000000000000000000000000000000000000000000000000000008152fd5b60046040517f31fa14c6000000000000000000000000000000000000000000000000000000008152fd5b60046040517fb7d09497000000000000000000000000000000000000000000000000000000008152fd5b346101105760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101105761073d6134b6565b50600435600052600160205260a06107586040600020612cbf565b6107ab60405180926fffffffffffffffffffffffffffffffff6080809263ffffffff8082511686528060208301511660208701528060408301511660408701526060820151166060860152015116910152565bf35b346101105760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576004358060005260016020526040600020600181019182549073ffffffffffffffffffffffffffffffffffffffff80831633036108f35760ff8360a01c166108c9577f28601d865dccc9f113e15a7185c1b38c085d598c71250d3337916a428536d77160206007936108c7977fffffffffffffffffffffffff00000000000000000000000000000000000000006fffffffffffffffffffffffffffffffff9716905567ffffffff000000007fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff885416178755604051908152a1600484015416920154169033906132ce565b005b60046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5c427cd9000000000000000000000000000000000000000000000000000000008152fd5b346101105761092b36612de5565b90806000526001602052604060002080549063ffffffff9182811642106000146109795760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60201c821690428211156109b15760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b6001015460a01c60ff1615610a8957505080600052600160205260406000206109dd83600b830161324f565b509182549073ffffffffffffffffffffffffffffffffffffffff9081831633036108f3576fffffffffffffffffffffffffffffffff93846002870154166108c9577f2734c8894183ae15778d25f03eb03cddaf925d0ee834245c1e03a328a89aeb7060406005936108c7997fffffffffffffffffffffffff0000000000000000000000000000000000000000600198168a5582519182526020820152a1015416920154169033906132ce565b81610a93826131e6565b164211610ac45760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b610acd906131e6565b164211156101105760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b34610110576101206020610b33610b1536612de5565b90610b1e6131fd565b5060005260018352600b60406000200161324f565b506040519182808093610b4582612ba4565b73ffffffffffffffffffffffffffffffffffffffff808254168352600182015491858401906fffffffffffffffffffffffffffffffff8481809694818096168152604089019260801c835260028501549660e0600660608c0197858b16895260808d019a60801c8b5260a060038201549d019c8d5260c0610bc860048301612d68565b9e019d8e5201549d019c8d526040519d51168d525116898c0152511660408a015251166060880152511660808601525160a085015251805160c0850152015160e083015251610100820152f35b346101105760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101105760243560443567ffffffffffffffff811161011057610c67903690600401612db4565b90600435600052600160205260406000209283549363ffffffff948581164210600014610cb85760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60201c85169042821115610cf05760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b6001015460a01c60ff1615610d295760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b84610d33826131e6565b164211611654575060043560005260016020526040600020600381019081546108c95760006020604051610d6681612b88565b8281520152610d8b83604051610d7b81612b88565b60018152600260208201526135b8565b8051600983015481149283159361163f575b50821561161d575b50506115f357817f636dccec5dc3756424ee9e96168463de735c92a85fb2642812ea6e0b2bd61763926040925581519060043582526020820152a181610de757005b610df2913691612c52565b906004356000526001602052604060002080548281164210600014610e3b5760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60201c82169042821115610e735760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b6001015460a01c60ff1615610eac5760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b81610eb6826131e6565b164211610ac45750506004356000526001602052604060002090600382015480156115f3578151600b840154036115c95760405190610ef482612b6c565b60006040830152600060a0830152600684015482526fffffffffffffffffffffffffffffffff60078501541660208301526fffffffffffffffffffffffffffffffff606083015260016080830152825160081c9060018201821161159a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610f9a6001610f83818601612c3a565b94610f916040519687612bf9565b01808552612c3a565b0136602084013760005b845181101561123757610fb781866132a7565b5190610fc682600b890161324f565b5091610fd58160081c866132a7565b51600160ff83161b8082161461120d57610ffb90600160ff84161b179160081c866132a7565b526110118361100c60048501612d68565b6135b8565b805160018114806111ff575b6111e857600684015491602060405191818301938452015160408201526040815261104781612bdd565b5190201861105481613499565b6003840154036111f45760801c60018301549080156111e85761108d60808801516fffffffffffffffffffffffffffffffff84166132bb565b61109b8260608a01516132bb565b90818110156111a2575b5050611171936110c7826fffffffffffffffffffffffffffffffff8516612f79565b88511161119a5760a088015160208901518114611191578261111291611167958260808d01526fffffffffffffffffffffffffffffffff811660608d015260801c60408c015261329a565b6020890151809111611176575b506002016fffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffffffffffff0000000000000000000000000000000082541617905560a087015161329a565b60a0860152612f0d565b610fa4565b600291925061118a9060a08a015190612fe2565b919061111f565b50505050612f0d565b505050612f0d565b036111be578160801c6040880151116111be576111718a6110a5565b60046040517fca428236000000000000000000000000000000000000000000000000000000008152fd5b50506111719150612f0d565b506111719150612f0d565b50600160208301511461101d565b60046040517f063c8ab3000000000000000000000000000000000000000000000000000000008152fd5b505090916fffffffffffffffffffffffffffffffff60608401511661129c600286019182906fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b6fffffffffffffffffffffffffffffffff6080850151167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055600184015493740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff861617600182015560005b83517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081810190811161159a578210156113755761136182866132a7565b510361120d5761137090612f0d565b611322565b505092909391805190817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81011161159a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6113d39201906132a7565b51600160ff8651161b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820191821161159a570361120d5760a08101516020820151106115705760a09160208201519083830151918281116114f3575b50505061147861144e606083015184840151608085015191612fae565b809473ffffffffffffffffffffffffffffffffffffffff60018160058401541692015416906133a1565b01519060405191608083016004358452608060208501528451809152602060a0850195019060005b8181106114dd57505050604083015260608201527f59910662e012236ad53bd4a7844ec083eb64c4477c85386182b5b503eeedbb339181900390a1005b82518752602096870196909201916001016114a0565b6115689261150091612fe2565b906fffffffffffffffffffffffffffffffff85850151167fffffffffffffffffffffffffffffffff0000000000000000000000000000000060078801541617600787015573ffffffffffffffffffffffffffffffffffffffff806004880154169116906133a1565b848080611431565b60046040517fac59a90a000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60046040517f8129bbcd000000000000000000000000000000000000000000000000000000008152fd5b60046040517fea63ebbc000000000000000000000000000000000000000000000000000000008152fd5b600114915081611630575b508680610da5565b60019150602001511486611628565b6020830151600a909101541415925088610d9d565b610acd85916131e6565b346101105761166c36612de5565b908060005260019081602052604060002090600b82019361168d818661324f565b5073ffffffffffffffffffffffffffffffffffffffff928382541633036108f357859163ffffffff80875460201c16908142101561195b575b50506fffffffffffffffffffffffffffffffff968791015416958754907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9182810190811161159a57611719908a61324f565b50611724868b61324f565b9290926117b757818303611815575b505050875480156117e657019261174a848961324f565b9490946117b7576108c798600060068782604098817f2a0a5f509bc9b1f09c4172bec62e98d404d2f98b3977aa9b9a2bb243671f5fe29b5582015582600282015582600382015582600482015582600582015501555582519182526020820152a1600533920154166132ce565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b8161191e600693928a859454167fffffffffffffffffffffffff0000000000000000000000000000000000000000875416178655888601906118c68a85019282845416937fffffffffffffffffffffffffffffffff0000000000000000000000000000000094858354161782555460801c6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b60028701916002850191825416908354161782555460801c6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b600381015460038501556004840160048201808203611947575b50500154910155888080611733565b549055600581015460058501558c80611938565b90919360ff9088015460a01c1691821561197f575b50506108c957859188806116c6565b61198a9192506131e6565b164211158880611970565b346101105760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576119cc6134b6565b50600435600052600160205260a06119ea6001604060002001612d02565b6107ab60405180926080809173ffffffffffffffffffffffffffffffffffffffff81511684526020810151151560208501526fffffffffffffffffffffffffffffffff80604083015116604086015260608201511660608501520151910152565b3461011057611a5936612de5565b90806000526001602052604060002080549063ffffffff918281164210600014611aa75760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60201c82169042821115611adf5760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b6001015460a01c60ff1615610a89575050806000526001602052604060002091611b0c81600b850161324f565b509073ffffffffffffffffffffffffffffffffffffffff918281541633036108f35760028101908154916fffffffffffffffffffffffffffffffff948584169283156108c95786611b6b611b60868b613465565b9660801c809761337f565b168095019087821161159a57611bbf60019285906fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b0180549087821680611c2f575b507ff8daa50652e9e7fc7e0021bea02c37ee39e453b5580c070fd3ca257a166939b360808a8a8a8a8f8b8b611c0c84611c15948e600433920154166133a1565b54871c9061337f565b9160405194855260208501526040840152166060820152a1005b90939198979695949260028b01549a888c60801c9c16918c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0486118d0215830215610110577ff8daa50652e9e7fc7e0021bea02c37ee39e453b5580c070fd3ca257a166939b39c60809c611c1598611c0c968b96611cf8948b0281810615159190040190818110611d09577fffffffffffffffffffffffffffffffff0000000000000000000000000000000091611ce691612fe2565b925b16905533836005860154166133a1565b94969798999a509a50829450611bcc565b50507fffffffffffffffffffffffffffffffff00000000000000000000000000000000600092611ce8565b346101105760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576020611d78611d70612ca0565b600435613465565b6fffffffffffffffffffffffffffffffff60405191168152f35b34610110576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011057611dca612ca0565b60407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c3601126101105767ffffffffffffffff9060c43582811161011057611e16903690600401612d86565b9260e43590811161011057611e2f903690600401612db4565b906004356000526001602052604060002080549063ffffffff918281164210600014611e7f5760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b829060201c16908142101561221857505050600435600052600160205260406000209160088301549182612185575b50505073ffffffffffffffffffffffffffffffffffffffff60018201541633146108f3576fffffffffffffffffffffffffffffffff8316158015612163575b61213957600b810154926103e88410156108c957611f096131fd565b923384526fffffffffffffffffffffffffffffffff821660208501526fffffffffffffffffffffffffffffffff8516604085015260443560a0850152604051611f5181612b88565b6064358152608435602082015260c085015260a43560e08501526801000000000000000085101561210a5760018501600b840155611f9285600b850161324f565b9190916117b757845182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020808601516040870151608090811b7fffffffffffffffffffffffffffffffff000000000000000000000000000000009081166fffffffffffffffffffffffffffffffff9384161760018701556060890151828a0151908416921b1617600285015590977f6240129d8b257ecc07022e0f251b3e713a516f8b1e53a125b6ac0271f6aa621c9691956106439491926120bc929060069060e09060a081015160038501558d60c0820151805160048701550151600585015501519101558686169073ffffffffffffffffffffffffffffffffffffffff60053392015416612fef565b6040519485943386526004358a870152886040870152166060850152604435608085015260643560a085015260843560c085015260a43560e085015261012080610100860152840191612f3a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60046040517fe83664ea000000000000000000000000000000000000000000000000000000008152fd5b50600781015460801c6fffffffffffffffffffffffffffffffff841610611eed565b819060405160208101903360601b8252601481526121a281612b88565b519020926121e4575b5050036121ba57848080611eae565b60046040517f09bde339000000000000000000000000000000000000000000000000000000008152fd5b80925b602084359182811160051b9081521852602060406000209301928260051b820184106121e7579250505086806121ab565b6001015460a01c60ff1615610a895760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b346101105760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576020600054604051908152f35b346101105760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011057600435600052600160205260406000206122d581612cbf565b906122e260018201612d02565b9060405160e0810181811067ffffffffffffffff82111761210a5760405273ffffffffffffffffffffffffffffffffffffffff90816004840154168152816005840154169060208101918252600684015491604082019283526007850154928460608401926fffffffffffffffffffffffffffffffff9687958688168652608081019760801c885260088a01549960a082019a8b5260090161238390612d68565b9a60c082019b8c526040519c8d6123df916fffffffffffffffffffffffffffffffff6080809263ffffffff8082511686528060208301511660208701528060408301511660408701526060820151166060860152015116910152565b805173ffffffffffffffffffffffffffffffffffffffff1660a08e01526020810151151560c08e015260408101516fffffffffffffffffffffffffffffffff90811660e08f01526060820151166101008e0152608001516101208d015251166101408b015251166101608901525161018088015251166101a086015251166101c0840152516101e08301525180516102008301526020015161022082015261024090f35b346101105760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610110576004356fffffffffffffffffffffffffffffffff8116810361011057602435907fffffffffffffffffffffffffffffffff0000000000000000000000000000000080831680930361011057602092604051918483019360801b168352603082015282815261251f81612b88565b51905190828110612534575b50604051908152f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90830360031b1b168261252b565b346101105760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101105760243567ffffffffffffffff81116101105736602382011215610110576125c3903690602481600401359101612c52565b6004356000526001602052604060002080549063ffffffff9182811642106000146126125760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b60201c8216904282111561264a5760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b6001015460a01c60ff16156126835760046040517fbaf3f0f7000000000000000000000000000000000000000000000000000000008152fd5b8161268d826131e6565b164211610ac457826004356000526001602052604060002090600382015480156115f3578151600b840154036115c957604051906126ca82612b6c565b60006040830152600060a0830152600684015482526fffffffffffffffffffffffffffffffff60078501541660208301526fffffffffffffffffffffffffffffffff606083015260016080830152825160081c9060018201821161159a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06127596001610f83818601612c3a565b0136602084013760005b84518110156128c75761277681866132a7565b519061278582600b890161324f565b50916127948160081c866132a7565b51600160ff83161b8082161461120d576127ba90600160ff84161b179160081c866132a7565b526127cb8361100c60048501612d68565b805160018114806128b9575b6128a257600684015491602060405191818301938452015160408201526040815261280181612bdd565b5190201861280e81613499565b6003840154036128ae5760801c60018301549080156128a25761284760808801516fffffffffffffffffffffffffffffffff84166132bb565b6128558260608a01516132bb565b9081811015612886575b5050612881936110c7826fffffffffffffffffffffffffffffffff8516612f79565b612763565b036111be578160801c6040880151116111be576128818a61285f565b50506128819150612f0d565b506128819150612f0d565b5060016020830151146127d7565b505090916fffffffffffffffffffffffffffffffff60608401511661292c600286019182906fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b6fffffffffffffffffffffffffffffffff6080850151167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055600184015493740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff861617600182015560005b83517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081810190811161159a57821015612a05576129f182866132a7565b510361120d57612a0090612f0d565b6129b2565b5050848484805190817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81011161159a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612a629201906132a7565b51600160ff8651161b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820191821161159a570361120d5760a08101516020820151106115705760a0916020820151908383015191828111612b57575b505050612add61144e606083015184840151608085015191612fae565b01519060405191608083016004358452608060208501528451809152602060a0850195019060005b818110612b41577f59910662e012236ad53bd4a7844ec083eb64c4477c85386182b5b503eeedbb338680898888604084015260608301520390a1005b8251875260209687019690920191600101612b05565b612b649261150091612fe2565b848080612ac0565b60c0810190811067ffffffffffffffff82111761210a57604052565b6040810190811067ffffffffffffffff82111761210a57604052565b610100810190811067ffffffffffffffff82111761210a57604052565b60a0810190811067ffffffffffffffff82111761210a57604052565b6060810190811067ffffffffffffffff82111761210a57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761210a57604052565b67ffffffffffffffff811161210a5760051b60200190565b9291612c5d82612c3a565b91612c6b6040519384612bf9565b829481845260208094019160051b810192831161011057905b828210612c915750505050565b81358152908301908301612c84565b602435906fffffffffffffffffffffffffffffffff8216820361011057565b90604051612ccc81612bc1565b608081935463ffffffff8082168452808260201c166020850152808260401c1660408501528160601c166060840152811c910152565b90604051612d0f81612bc1565b60806002829460ff815473ffffffffffffffffffffffffffffffffffffffff8116865260a01c161515602085015260018101546fffffffffffffffffffffffffffffffff81166040860152831c60608501520154910152565b90604051612d7581612b88565b602060018294805484520154910152565b9181601f840112156101105782359167ffffffffffffffff8311610110576020838186019501011161011057565b9181601f840112156101105782359167ffffffffffffffff8311610110576020808501948460051b01011161011057565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040910112610110576004359060243590565b6101243563ffffffff811681036101105790565b6101043563ffffffff811681036101105790565b6101443563ffffffff811681036101105790565b6101643563ffffffff811681036101105790565b610184356fffffffffffffffffffffffffffffffff811681036101105790565b6084356fffffffffffffffffffffffffffffffff811681036101105790565b6064356fffffffffffffffffffffffffffffffff811681036101105790565b60243573ffffffffffffffffffffffffffffffffffffffff811681036101105790565b60043573ffffffffffffffffffffffffffffffffffffffff811681036101105790565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461159a5760010190565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b6fffffffffffffffffffffffffffffffff90700100000000000000000000000000000001811182021583021561011057020490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04811182021583021561011057020490565b9190820391821161159a57565b73ffffffffffffffffffffffffffffffffffffffff9092919216916040928351907f70a08231000000000000000000000000000000000000000000000000000000008083523060048401526020938484602481865afa9384156131db579085916000956131a8575b5060646000918951907f23b872dd000000000000000000000000000000000000000000000000000000008252600482015230602482015288604482015282865af13d15601f3d116001600051141617161561314b578390602487518094819382523060048301525afa9081156131405760009161310b575b506130da9250612fe2565b036130e25750565b600490517fad709933000000000000000000000000000000000000000000000000000000008152fd5b919282813d8311613139575b6131218183612bf9565b810103126131365750906130da9151386130cf565b80fd5b503d613117565b85513d6000823e3d90fd5b6064848751907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b9182819692963d83116131d4575b6131c08183612bf9565b810103126131365750519284906064613057565b503d6131b6565b87513d6000823e3d90fd5b906201518063ffffffff8093160191821161159a57565b6040519061320a82612ba4565b8160e06000918281528260208201528260408201528260608201528260808201528260a082015260405161323d81612b88565b83815283602082015260c08201520152565b805482101561326b576000526007602060002091020190600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190820180921161159a57565b805182101561326b5760209160051b010190565b8181029291811591840414171561159a57565b60009182604492602095604051937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af13d15601f3d116001600051141617161561332157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b6fffffffffffffffffffffffffffffffff918216908216039190821161159a57565b73ffffffffffffffffffffffffffffffffffffffff9092919216916040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481875afa90811561345957600091613428575b50828110613420575b50811561341b57613419926132ce565b565b505050565b915038613409565b906020823d8211613451575b8161344160209383612bf9565b8101031261313657505138613400565b3d9150613434565b6040513d6000823e3d90fd5b9061349691600052600160205260406000205463ffffffff8160801c9181421691808260601c169160401c166134f7565b90565b60405160208101918252602081526134b081612b88565b51902090565b604051906134c382612bc1565b60006080838281528260208201528260408201528260608201520152565b63ffffffff918216908216039190821161159a57565b63ffffffff93929091908481168583168111156135175750505050505090565b8386161061352a57505050505050600090565b6fffffffffffffffffffffffffffffffff80809716941694670de0b6b3a764000095807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048611810215870215610110576135a58561359f6135ae976135996135b49b87968c0204809b612fe2565b966134e1565b956134e1565b16921690612fae565b9061329a565b1690565b60408051916135c683612b88565b6000908184528160208095015284158015613728575b61371757825194848087019280518452015184870152606086015260608552608085019467ffffffffffffffff95818110878211176136ea5784525182918291906007611770fa3d156136e1573d9485116136b457825194613665857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160187612bf9565b85523d828587013e5b1561369b578184805181010312613136575080519261368c84612b88565b82810151845201519082015290565b505191506001906136ab83612b88565b81835282015290565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6060945061366e565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b50505191506001906136ab83612b88565b5080511580156135dc575083810151156135dc56fea26469706673582212200f5bf4f298a1f7b93cc1bf2d82de96f347dcea3144606d482f036217a2ba24ab64736f6c63430008130033