ETH Price: $3,424.11 (+0.97%)
Gas: 50 Gwei

Contract

0xD2A34731586bD10B645f870f4C9DcAF4F9e3823C
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
End Auction177709602023-07-25 15:19:35221 days ago1690298375IN
0xD2A34731...4F9e3823C
0 ETH0.0065135239.91520241
End Auction177709582023-07-25 15:19:11221 days ago1690298351IN
0xD2A34731...4F9e3823C
0 ETH0.0083967239.9225989
Set Weights177696382023-07-25 10:53:35221 days ago1690282415IN
0xD2A34731...4F9e3823C
0 ETH0.0007167423.62608119
0x60a06040167771472023-03-07 14:54:59361 days ago1678200899IN
 Create: Liquidator
0 ETH0.1034992239.13724263

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Liquidator

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 4 of 9 : Liquidator.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: BUSL-1.1
 */
pragma solidity ^0.8.13;

import { LogExpMath } from "./utils/LogExpMath.sol";
import { IFactory } from "./interfaces/IFactory.sol";
import { ERC20, SafeTransferLib } from "../lib/solmate/src/utils/SafeTransferLib.sol";
import { IVault } from "./interfaces/IVault.sol";
import { ILendingPool } from "./interfaces/ILendingPool.sol";
import { Owned } from "lib/solmate/src/auth/Owned.sol";

/**
 * @title Liquidator
 * @author Pragma Labs
 * @notice The liquidator holds the execution logic and storage of all things related to liquidating Arcadia Vaults.
 * Ensure your total value denomination remains above the liquidation threshold, or risk being liquidated!
 */
contract Liquidator is Owned {
    using SafeTransferLib for ERC20;

    /* //////////////////////////////////////////////////////////////
                                STORAGE
    ////////////////////////////////////////////////////////////// */

    // The contract address of the Factory.
    address public immutable factory;
    // Sets the begin price of the auction.
    // Defined as a percentage of openDebt, 2 decimals precision -> 150 = 150%.
    uint16 public startPriceMultiplier;
    // Sets the minimum price the auction converges to.
    // Defined as a percentage of openDebt, 2 decimals precision -> 60 = 60%.
    uint8 public minPriceMultiplier;
    // The base of the auction price curve (exponential).
    // Determines how fast the auction price drops per second, 18 decimals precision.
    uint64 public base;
    // Maximum time that the auction declines, after which price is equal to the minimum price set by minPriceMultiplier.
    // Time in seconds, with 0 decimals precision.
    uint16 public cutoffTime;
    // Fee paid to the Liquidation Initiator.
    // Defined as a fraction of the openDebt with 2 decimals precision.
    // Absolute fee can be further capped to a max amount by the creditor.
    uint8 public initiatorRewardWeight;
    // Penalty the Vault owner has to pay to the trusted Creditor on top of the open Debt for being liquidated.
    // Defined as a fraction of the openDebt with 2 decimals precision.
    uint8 public penaltyWeight;

    // Map vault => auctionInformation.
    mapping(address => AuctionInformation) public auctionInformation;

    // Struct with additional information about the auction of a specific Vault.
    struct AuctionInformation {
        uint128 openDebt; // The open debt, same decimal precision as baseCurrency.
        uint32 startTime; // The timestamp the auction started.
        bool inAuction; // Flag indicating if the auction is still ongoing.
        uint80 maxInitiatorFee; // The max initiation fee, same decimal precision as baseCurrency.
        address baseCurrency; // The contract address of the baseCurrency.
        uint16 startPriceMultiplier; // 2 decimals precision.
        uint8 minPriceMultiplier; // 2 decimals precision.
        uint8 initiatorRewardWeight; // 2 decimals precision.
        uint8 penaltyWeight; // 2 decimals precision.
        uint16 cutoffTime; // Maximum time that the auction declines.
        address originalOwner; // The original owner of the Vault.
        address trustedCreditor; // The creditor that issued the debt.
        uint64 base; // Determines how fast the auction price drops over time.
    }

    /* //////////////////////////////////////////////////////////////
                                EVENTS
    ////////////////////////////////////////////////////////////// */

    event WeightsSet(uint8 initiatorRewardWeight, uint8 penaltyWeight);
    event AuctionCurveParametersSet(uint64 base, uint16 cutoffTime);
    event StartPriceMultiplierSet(uint16 startPriceMultiplier);
    event MinimumPriceMultiplierSet(uint8 minPriceMultiplier);
    event AuctionStarted(address indexed vault, address indexed creditor, address baseCurrency, uint128 openDebt);
    event AuctionFinished(
        address indexed vault,
        address indexed creditor,
        address baseCurrency,
        uint128 price,
        uint128 badDebt,
        uint128 initiatorReward,
        uint128 liquidationPenalty,
        uint128 remainder
    );

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

    constructor(address factory_) Owned(msg.sender) {
        factory = factory_;
        initiatorRewardWeight = 1;
        penaltyWeight = 5;
        startPriceMultiplier = 150;
        minPriceMultiplier = 60;
        cutoffTime = 14_400; //4 hours
        base = 999_807_477_651_317_446; //3600s halflife, 14_400 cutoff
    }

    /*///////////////////////////////////////////////////////////////
                        MANAGE AUCTION SETTINGS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Sets the liquidation weights.
     * @param initiatorRewardWeight_ Fee paid to the Liquidation Initiator.
     * @param penaltyWeight_ Penalty paid by the Vault owner to the trusted Creditor.
     * @dev Each weight has 2 decimals precision (50 equals 0,5 or 50%).
     */
    function setWeights(uint256 initiatorRewardWeight_, uint256 penaltyWeight_) external onlyOwner {
        require(initiatorRewardWeight_ + penaltyWeight_ <= 11, "LQ_SW: Weights Too High");

        initiatorRewardWeight = uint8(initiatorRewardWeight_);
        penaltyWeight = uint8(penaltyWeight_);

        emit WeightsSet(uint8(initiatorRewardWeight_), uint8(penaltyWeight_));
    }

    /**
     * @notice Sets the parameters (base and cutOffTime) of the auction price curve (decreasing power function).
     * @param halfLifeTime The base is not set directly, but it's derived from a more intuitive parameter, the halfLifeTime:
     * The time ΔT_hl (in seconds with 0 decimals) it takes for the power function to halve in value.
     * @dev The relation between the base and the halfLife time (ΔT_hl):
     * The power function is defined as: N(t) = N(0) * (1/2)^(t/ΔT_hl).
     * Or simplified: N(t) = N(O) * base^t => base = 1/[2^(1/ΔT_hl)].
     * @param cutoffTime_ The Maximum time that the auction declines,
     * after which price is equal to the minimum price set by minPriceMultiplier.
     * @dev Setting a very short cutoffTime can be used by rogue owners to rug the junior tranche!!
     * Therefore the cutoffTime has hardcoded constraints.
     * @dev All calculations are done with 18 decimals precision.
     */
    function setAuctionCurveParameters(uint16 halfLifeTime, uint16 cutoffTime_) external onlyOwner {
        //Checks that new parameters are within reasonable boundaries.
        require(halfLifeTime > 120, "LQ_SACP: halfLifeTime too low"); // 2 minutes
        require(halfLifeTime < 28_800, "LQ_SACP: halfLifeTime too high"); // 8 hours
        require(cutoffTime_ > 3600, "LQ_SACP: cutoff too low"); // 1 hour
        require(cutoffTime_ < 64_800, "LQ_SACP: cutoff too high"); // 18 hours

        //Derive base from the halfLifeTime.
        uint64 base_ = uint64(1e18 * 1e18 / LogExpMath.pow(2 * 1e18, 1e18 / halfLifeTime));

        //Check that LogExpMath.pow(base, timePassed) does not error at cutoffTime (due to numbers smaller than minimum precision).
        //Since LogExpMath.pow is a strictly decreasing function checking the power function at cutoffTime
        //guarantees that the function does not revert on all timestamps between start of the auction and the cutoffTime.
        LogExpMath.pow(base_, uint256(cutoffTime_) * 1e18);

        //Store the new parameters.
        base = base_;
        cutoffTime = cutoffTime_;

        emit AuctionCurveParametersSet(base_, cutoffTime_);
    }

    /**
     * @notice Sets the start price multiplier for the liquidator.
     * @param startPriceMultiplier_ The new start price multiplier, with 2 decimals precision.
     * @dev The start price multiplier is a multiplier that is used to increase the initial price of the auction.
     * Since the value of all assets are discounted with the liquidation factor, and because pricing modules will take a conservative
     * approach to price assets (eg. floor-prices for NFTs), the actual value of the assets being auctioned might be substantially higher
     * as the open debt. Hence the auction starts at a multiplier of the openDebt, but decreases rapidly (exponential decay).
     */
    function setStartPriceMultiplier(uint16 startPriceMultiplier_) external onlyOwner {
        require(startPriceMultiplier_ > 100, "LQ_SSPM: multiplier too low");
        require(startPriceMultiplier_ < 301, "LQ_SSPM: multiplier too high");
        startPriceMultiplier = startPriceMultiplier_;

        emit StartPriceMultiplierSet(startPriceMultiplier_);
    }

    /**
     * @notice Sets the minimum price multiplier for the liquidator.
     * @param minPriceMultiplier_ The new minimum price multiplier, with 2 decimals precision.
     * @dev The minimum price multiplier sets a lower bound to which the auction price converges.
     */
    function setMinimumPriceMultiplier(uint8 minPriceMultiplier_) external onlyOwner {
        require(minPriceMultiplier_ < 91, "LQ_SMPM: multiplier too high");
        minPriceMultiplier = minPriceMultiplier_;

        emit MinimumPriceMultiplierSet(minPriceMultiplier_);
    }

    /*///////////////////////////////////////////////////////////////
                            AUCTION LOGIC
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Called by a Creditor to start an auction to liquidate collateral of a vault.
     * @param vault The contract address of the Vault to liquidate.
     * @param openDebt The open debt taken by `originalOwner`.
     * @param maxInitiatorFee The upper limit for the fee paid to the Liquidation Initiator, set by the trusted Creditor.
     * @dev This function is called by the Creditor who is owed the debt issued against the Vault.
     */
    function startAuction(address vault, uint256 openDebt, uint80 maxInitiatorFee) public {
        require(!auctionInformation[vault].inAuction, "LQ_SA: Auction already ongoing");

        //Avoid possible re-entrance with the same vault address.
        auctionInformation[vault].inAuction = true;

        //A malicious msg.sender can pass a self created contract as vault (not an actual Arcadia-Vault) that returns true on liquidateVault().
        //This would successfully start an auction, but as long as no collision with an actual Arcadia-vault contract address is found, this is not an issue.
        //The malicious non-vault would be in auction indefinitely, but does not block any 'real' auctions of Arcadia-Vaults.
        //One exception is if an attacker finds a pre-image of his custom contract with the same contract address of an Arcadia-Vault (deployed via create2).
        //The attacker could in theory: start auction of malicious contract, self-destruct and create Arcadia-vault with identical contract address.
        //This Vault could never be auctioned since auctionInformation[vault].inAuction would return true.
        //Finding such a collision requires finding a collision of the keccak256 hash function.
        (address originalOwner, address baseCurrency, address trustedCreditor) = IVault(vault).liquidateVault(openDebt);

        //Check that msg.sender is indeed the Creditor of the Vault.
        require(trustedCreditor == msg.sender, "LQ_SA: Unauthorised");

        auctionInformation[vault].openDebt = uint128(openDebt);
        auctionInformation[vault].startTime = uint32(block.timestamp);
        auctionInformation[vault].maxInitiatorFee = maxInitiatorFee;
        auctionInformation[vault].baseCurrency = baseCurrency;
        auctionInformation[vault].startPriceMultiplier = startPriceMultiplier;
        auctionInformation[vault].minPriceMultiplier = minPriceMultiplier;
        auctionInformation[vault].initiatorRewardWeight = initiatorRewardWeight;
        auctionInformation[vault].penaltyWeight = penaltyWeight;
        auctionInformation[vault].cutoffTime = cutoffTime;
        auctionInformation[vault].originalOwner = originalOwner;
        auctionInformation[vault].trustedCreditor = msg.sender;
        auctionInformation[vault].base = base;

        emit AuctionStarted(vault, trustedCreditor, baseCurrency, uint128(openDebt));
    }

    /**
     * @notice Function returns the current auction price of a vault.
     * @param vault The contract address of the vault.
     * @return price the total price for which the vault can be purchased.
     * @return inAuction returns false when the vault is not being auctioned.
     * @dev We use a dutch auction: price constantly decreases and the first bidder buys the vault
     * and immediately ends the auction.
     */
    function getPriceOfVault(address vault) public view returns (uint256 price, bool inAuction) {
        inAuction = auctionInformation[vault].inAuction;

        if (!inAuction) {
            return (0, false);
        }

        price = _calcPriceOfVault(auctionInformation[vault]);
    }

    /**
     * @notice Function returns the current auction price given time passed and the openDebt.
     * @param auctionInfo The auction information.
     * @return price The total price for which the vault can be purchased.
     * @dev We use a dutch auction: price constantly decreases and the first bidder buys the vault and immediately ends the auction.
     * @dev Price P(t) decreases exponentially over time: P(t) = openDebt * [(SPM - MPM) * base^t + MPM]:
     * SPM: The startPriceMultiplier defines the initial price: P(0) = openDebt * SPM (2 decimals precision).
     * MPM: The minPriceMultiplier defines the asymptotic end price for P(∞) = openDebt * MPM (2 decimals precision).
     * base: defines how fast the exponential curve decreases (18 decimals precision).
     * t: time passed since start auction (in seconds, 18 decimals precision).
     * @dev LogExpMath was made in solidity 0.7, where operations were unchecked.
     */
    function _calcPriceOfVault(AuctionInformation memory auctionInfo) internal view returns (uint256 price) {
        //Time passed is a difference of two Uint32 -> can't overflow.
        uint256 timePassed;
        unchecked {
            timePassed = block.timestamp - auctionInfo.startTime; //time duration in seconds.

            if (timePassed > auctionInfo.cutoffTime) {
                //Cut-off time passed -> return the minimal value defined by minPriceMultiplier (2 decimals precision).
                //No overflow possible: uint128 * uint8.
                price = uint256(auctionInfo.openDebt) * auctionInfo.minPriceMultiplier / 1e2;
            } else {
                //Bring to 18 decimals precision for LogExpMath.pow()
                //No overflow possible: uin32 * uint64.
                timePassed = timePassed * 1e18;

                //pow(base, timePassed) has 18 decimals and is strictly smaller than 1 (-> smaller as 1e18).
                //No overflow possible: uint128 * uint64 * uint8.
                //Multipliers have 2 decimals precision and LogExpMath.pow() has 18 decimals precision,
                //hence we need to divide the result by 1e20.
                price = auctionInfo.openDebt
                    * (
                        LogExpMath.pow(auctionInfo.base, timePassed)
                            * (auctionInfo.startPriceMultiplier - auctionInfo.minPriceMultiplier)
                            + 1e18 * uint256(auctionInfo.minPriceMultiplier)
                    ) / 1e20;
            }
        }
    }

    /**
     * @notice Function a user (the bidder) calls to buy the vault and end the auction.
     * @param vault The contract address of the vault.
     * @dev We use a dutch auction: price constantly decreases and the first bidder buys the vault
     * And immediately ends the auction.
     */
    function buyVault(address vault) external {
        AuctionInformation memory auctionInformation_ = auctionInformation[vault];
        require(auctionInformation_.inAuction, "LQ_BV: Not for sale");

        uint256 priceOfVault = _calcPriceOfVault(auctionInformation_);
        //Stop the auction, this will prevent any possible reentrance attacks.
        auctionInformation[vault].inAuction = false;

        //Transfer funds, equal to the current auction price from the bidder to the Creditor contract.
        //The bidder should have approved the Liquidation contract for at least an amount of priceOfVault.
        ERC20(auctionInformation_.baseCurrency).safeTransferFrom(
            msg.sender, auctionInformation_.trustedCreditor, priceOfVault
        );

        (uint256 badDebt, uint256 liquidationInitiatorReward, uint256 liquidationPenalty, uint256 remainder) =
        calcLiquidationSettlementValues(auctionInformation_.openDebt, priceOfVault, auctionInformation_.maxInitiatorFee);

        ILendingPool(auctionInformation_.trustedCreditor).settleLiquidation(
            vault, auctionInformation_.originalOwner, badDebt, liquidationInitiatorReward, liquidationPenalty, remainder
        );

        //Change ownership of the auctioned vault to the bidder.
        IFactory(factory).safeTransferFrom(address(this), msg.sender, vault);

        emit AuctionFinished(
            vault,
            auctionInformation_.trustedCreditor,
            auctionInformation_.baseCurrency,
            uint128(priceOfVault),
            uint128(badDebt),
            uint128(liquidationInitiatorReward),
            uint128(liquidationPenalty),
            uint128(remainder)
        );
    }

    /**
     * @notice End an unsuccessful auction after the cutoffTime has passed.
     * @param vault The contract address of the vault.
     * @param to The address to which the vault will be transferred.
     * @dev This is an emergency process, and can not be triggered under normal operation.
     * The auction will be stopped and the vault will be transferred to the provided address.
     * The junior tranche of the liquidity pool will pay for the bad debt.
     * The protocol will sell/auction the vault in another way to recover the debt.
     * The protocol will later "donate" these proceeds back to the junior tranche and/or other
     * impacted Tranches, this last step is not enforced by the smart contracts.
     * While this process is not fully trustless, it is the only way to solve an extreme unhappy flow,
     * where an auction did not end within cutoffTime (due to market or technical reasons).
     */
    function endAuction(address vault, address to) external onlyOwner {
        AuctionInformation memory auctionInformation_ = auctionInformation[vault];
        require(auctionInformation_.inAuction, "LQ_EA: Not for sale");

        uint256 timePassed;
        unchecked {
            timePassed = block.timestamp - auctionInformation_.startTime;
        }
        require(timePassed > cutoffTime, "LQ_EA: Auction not expired");

        //Stop the auction, this will prevent any possible reentrance attacks.
        auctionInformation[vault].inAuction = false;

        (uint256 badDebt, uint256 liquidationInitiatorReward, uint256 liquidationPenalty, uint256 remainder) =
            calcLiquidationSettlementValues(auctionInformation_.openDebt, 0, auctionInformation_.maxInitiatorFee); //priceOfVault is zero.

        ILendingPool(auctionInformation_.trustedCreditor).settleLiquidation(
            vault, auctionInformation_.originalOwner, badDebt, liquidationInitiatorReward, liquidationPenalty, remainder
        );

        //Change ownership of the auctioned vault to the protocol owner.
        IFactory(factory).safeTransferFrom(address(this), to, vault);

        emit AuctionFinished(
            vault,
            auctionInformation_.trustedCreditor,
            auctionInformation_.baseCurrency,
            0,
            uint128(badDebt),
            uint128(liquidationInitiatorReward),
            uint128(liquidationPenalty),
            uint128(remainder)
        );
    }

    /**
     * @notice Calculates how the liquidation needs to be further settled with the Creditor, Original owner and Service providers.
     * @param openDebt The open debt taken by `originalOwner`.
     * @param priceOfVault The final selling price of the Vault.
     * @return badDebt The amount of liabilities that was not recouped by the auction.
     * @return liquidationInitiatorReward The Reward for the Liquidation Initiator.
     * @return liquidationPenalty The additional penalty the `originalOwner` has to pay to the protocol.
     * @return remainder Any funds remaining after the auction are returned back to the `originalOwner`.
     * @dev All values are denominated in the baseCurrency of the Vault.
     * @dev We use a dutch auction: price constantly decreases and the first bidder buys the vault
     * And immediately ends the auction.
     */
    function calcLiquidationSettlementValues(uint256 openDebt, uint256 priceOfVault, uint88 maxInitiatorFee)
        public
        view
        returns (uint256 badDebt, uint256 liquidationInitiatorReward, uint256 liquidationPenalty, uint256 remainder)
    {
        //openDebt is a uint128 -> all calculations can be unchecked.
        unchecked {
            //Liquidation Initiator Reward is always paid out, independent of the final auction price.
            //The reward is calculated as a fixed percentage of open debt, but capped on the upside (maxInitiatorFee).
            liquidationInitiatorReward = openDebt * initiatorRewardWeight / 100;
            liquidationInitiatorReward =
                liquidationInitiatorReward > maxInitiatorFee ? maxInitiatorFee : liquidationInitiatorReward;

            //Final Auction price should at least cover the original debt and Liquidation Initiator Reward.
            //Otherwise there is bad debt.
            if (priceOfVault < openDebt + liquidationInitiatorReward) {
                badDebt = openDebt + liquidationInitiatorReward - priceOfVault;
            } else {
                liquidationPenalty = openDebt * penaltyWeight / 100;
                remainder = priceOfVault - openDebt - liquidationInitiatorReward;

                //Check if the remainder can cover the full liquidation penalty.
                if (remainder > liquidationPenalty) {
                    //If yes, calculate the final remainder.
                    remainder -= liquidationPenalty;
                } else {
                    //If not, there is no remainder for the originalOwner.
                    liquidationPenalty = remainder;
                    remainder = 0;
                }
            }
        }
    }
}

File 2 of 9 : Owned.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

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

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

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

    constructor(address _owner) {
        owner = _owner;

        emit OwnershipTransferred(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function transferOwnership(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnershipTransferred(msg.sender, newOwner);
    }
}

File 3 of 9 : 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);
    }
}

File 4 of 9 : 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");
    }
}

File 5 of 9 : IFactory.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity ^0.8.13;

interface IFactory {
    /**
     * @notice View function returning if an address is a vault.
     * @param vault The address to be checked.
     * @return bool Whether the address is a vault or not.
     */
    function isVault(address vault) external view returns (bool);

    /**
     * @notice Function used to transfer a vault between users.
     * @dev This method transfers a vault not on id but on address and also transfers the vault proxy contract to the new owner.
     * @param from sender.
     * @param to target.
     * @param vault The address of the vault that is about to be transferred.
     */
    function safeTransferFrom(address from, address to, address vault) external;

    /**
     * @notice Function called by a Vault at the start of a liquidation to transfer ownership.
     * @param liquidator The contract address of the liquidator.
     */
    function liquidate(address liquidator) external;
}

File 6 of 9 : ILendingPool.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity ^0.8.13;

interface ILendingPool {
    /**
     * @notice Settles the liquidation after the auction is finished with; the Creditor, Original owner and Service providers.
     * @param vault The contract address of the vault.
     * @param originalOwner The original owner of the vault before the auction.
     * @param badDebt The amount of liabilities that was not recouped by the auction.
     * @param liquidationInitiatorReward The Reward for the Liquidation Initiator.
     * @param liquidationPenalty The additional penalty the `originalOwner` has to pay to the protocol.
     * @param remainder Any funds remaining after the auction are returned back to the `originalOwner`.
     */
    function settleLiquidation(
        address vault,
        address originalOwner,
        uint256 badDebt,
        uint256 liquidationInitiatorReward,
        uint256 liquidationPenalty,
        uint256 remainder
    ) external;
}

File 7 of 9 : IVault.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity ^0.8.13;

interface IVault {
    /**
     * @notice Returns the Vault version.
     * @return version The Vault version.
     */
    function vaultVersion() external view returns (uint16);

    /**
     * @notice Initiates the variables of the vault.
     * @param owner The tx.origin: the sender of the 'createVault' on the factory.
     * @param registry The 'beacon' contract to which should be looked at for external logic.
     * @param vaultVersion The version of the vault logic.
     * @param baseCurrency The Base-currency in which the vault is denominated.
     */
    function initialize(address owner, address registry, uint16 vaultVersion, address baseCurrency) external;

    /**
     * @notice Stores a new address in the EIP1967 implementation slot & updates the vault version.
     * @param newImplementation The contract with the new vault logic.
     * @param newRegistry The MainRegistry for this specific implementation (might be identical as the old registry)
     * @param data Arbitrary data, can contain instructions to execute when updating Vault to new logic
     * @param newVersion The new version of the vault logic.
     */
    function upgradeVault(address newImplementation, address newRegistry, uint16 newVersion, bytes calldata data)
        external;

    /**
     * @notice Transfers ownership of the contract to a new account.
     * @param newOwner The new owner of the Vault.
     */
    function transferOwnership(address newOwner) external;

    /**
     * @notice Function called by Liquidator to start liquidation of the Vault.
     * @param openDebt The open debt taken by `originalOwner` at moment of liquidation at trustedCreditor.
     * @return originalOwner The original owner of this vault.
     * @return baseCurrency The baseCurrency in which the vault is denominated.
     * @return trustedCreditor The account or contract that is owed the debt.
     */
    function liquidateVault(uint256 openDebt) external returns (address, address, address);
}

File 8 of 9 : BalancerErrors.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.13;

// solhint-disable

/**
 * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are
 * supported.
 */
function _require(bool condition, uint256 errorCode) pure {
    if (!condition) {
        _revert(errorCode);
    }
}

/**
 * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.
 */
function _revert(uint256 errorCode) pure {
    // We're going to dynamically create a revert string based on the error code, with the following format:
    // 'BAL#{errorCode}'
    // where the code is left-padded with zeroes to three digits (so they range from 000 to 999).
    //
    // We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a
    // number (8 to 16 bits) than the individual string characters.
    //
    // The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a
    // much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a
    // safe place to rely on it without worrying about how its usage might affect e.g. memory contents.
    assembly {
        // First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999
        // range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for
        // the '0' character.

        let units := add(mod(errorCode, 10), 0x30)

        errorCode := div(errorCode, 10)
        let tenths := add(mod(errorCode, 10), 0x30)

        errorCode := div(errorCode, 10)
        let hundreds := add(mod(errorCode, 10), 0x30)

        // With the individual characters, we can now construct the full string. The "BAL#" part is a known constant
        // (0x42414c23): we simply shift this by 24 (to provide space for the 3 bytes of the error code), and add the
        // characters to it, each shifted by a multiple of 8.
        // The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits
        // per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte
        // array).

        let revertReason := shl(200, add(0x42414c23000000, add(add(units, shl(8, tenths)), shl(16, hundreds))))

        // We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded
        // message will have the following layout:
        // [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ]

        // The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We
        // also write zeroes to the next 28 bytes of memory, but those are about to be overwritten.
        mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
        // Next is the offset to the location of the string, which will be placed immediately after (20 bytes away).
        mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
        // The string length is fixed: 7 characters.
        mstore(0x24, 7)
        // Finally, the string itself is stored.
        mstore(0x44, revertReason)

        // Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of
        // the encoded message is therefore 4 + 32 + 32 + 32 = 100.
        revert(0, 100)
    }
}

library Errors {
    // Math
    uint256 internal constant ADD_OVERFLOW = 0;
    uint256 internal constant SUB_OVERFLOW = 1;
    uint256 internal constant SUB_UNDERFLOW = 2;
    uint256 internal constant MUL_OVERFLOW = 3;
    uint256 internal constant ZERO_DIVISION = 4;
    uint256 internal constant DIV_INTERNAL = 5;
    uint256 internal constant X_OUT_OF_BOUNDS = 6;
    uint256 internal constant Y_OUT_OF_BOUNDS = 7;
    uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8;
    uint256 internal constant INVALID_EXPONENT = 9;

    // Input
    uint256 internal constant OUT_OF_BOUNDS = 100;
    uint256 internal constant UNSORTED_ARRAY = 101;
    uint256 internal constant UNSORTED_TOKENS = 102;
    uint256 internal constant INPUT_LENGTH_MISMATCH = 103;
    uint256 internal constant ZERO_TOKEN = 104;

    // Shared pools
    uint256 internal constant MIN_TOKENS = 200;
    uint256 internal constant MAX_TOKENS = 201;
    uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202;
    uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203;
    uint256 internal constant MINIMUM_BPT = 204;
    uint256 internal constant CALLER_NOT_VAULT = 205;
    uint256 internal constant UNINITIALIZED = 206;
    uint256 internal constant BPT_IN_MAX_AMOUNT = 207;
    uint256 internal constant BPT_OUT_MIN_AMOUNT = 208;
    uint256 internal constant EXPIRED_PERMIT = 209;

    // Pools
    uint256 internal constant MIN_AMP = 300;
    uint256 internal constant MAX_AMP = 301;
    uint256 internal constant MIN_WEIGHT = 302;
    uint256 internal constant MAX_STABLE_TOKENS = 303;
    uint256 internal constant MAX_IN_RATIO = 304;
    uint256 internal constant MAX_OUT_RATIO = 305;
    uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306;
    uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307;
    uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308;
    uint256 internal constant INVALID_TOKEN = 309;
    uint256 internal constant UNHANDLED_JOIN_KIND = 310;
    uint256 internal constant ZERO_INVARIANT = 311;
    uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312;
    uint256 internal constant ORACLE_NOT_INITIALIZED = 313;
    uint256 internal constant ORACLE_QUERY_TOO_OLD = 314;
    uint256 internal constant ORACLE_INVALID_INDEX = 315;
    uint256 internal constant ORACLE_BAD_SECS = 316;

    // Lib
    uint256 internal constant REENTRANCY = 400;
    uint256 internal constant SENDER_NOT_ALLOWED = 401;
    uint256 internal constant PAUSED = 402;
    uint256 internal constant PAUSE_WINDOW_EXPIRED = 403;
    uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404;
    uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405;
    uint256 internal constant INSUFFICIENT_BALANCE = 406;
    uint256 internal constant INSUFFICIENT_ALLOWANCE = 407;
    uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408;
    uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409;
    uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410;
    uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411;
    uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412;
    uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413;
    uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414;
    uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415;
    uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416;
    uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417;
    uint256 internal constant SAFE_ERC20_CALL_FAILED = 418;
    uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419;
    uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420;
    uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421;
    uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422;
    uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423;
    uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424;
    uint256 internal constant BUFFER_PERIOD_EXPIRED = 425;

    // Vault
    uint256 internal constant INVALID_POOL_ID = 500;
    uint256 internal constant CALLER_NOT_POOL = 501;
    uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502;
    uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503;
    uint256 internal constant INVALID_SIGNATURE = 504;
    uint256 internal constant EXIT_BELOW_MIN = 505;
    uint256 internal constant JOIN_ABOVE_MAX = 506;
    uint256 internal constant SWAP_LIMIT = 507;
    uint256 internal constant SWAP_DEADLINE = 508;
    uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509;
    uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510;
    uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511;
    uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512;
    uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513;
    uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514;
    uint256 internal constant INVALID_POST_LOAN_BALANCE = 515;
    uint256 internal constant INSUFFICIENT_ETH = 516;
    uint256 internal constant UNALLOCATED_ETH = 517;
    uint256 internal constant ETH_TRANSFER = 518;
    uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519;
    uint256 internal constant TOKENS_MISMATCH = 520;
    uint256 internal constant TOKEN_NOT_REGISTERED = 521;
    uint256 internal constant TOKEN_ALREADY_REGISTERED = 522;
    uint256 internal constant TOKENS_ALREADY_SET = 523;
    uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524;
    uint256 internal constant NONZERO_TOKEN_BALANCE = 525;
    uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526;
    uint256 internal constant POOL_NO_TOKENS = 527;
    uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528;

    // Fees
    uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600;
    uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601;
    uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602;
}

File 9 of 9 : LogExpMath.sol
// SPDX-License-Identifier: MIT
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.

// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pragma solidity ^0.8.13;

import "./BalancerErrors.sol";

/* solhint-disable */

/**
 * @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).
 *
 * Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural
 * exponentiation and logarithm (where the base is Euler's number).
 *
 * @author Fernando Martinelli - @fernandomartinelli
 * @author Sergio Yuhjtman - @sergioyuhjtman
 * @author Daniel Fernandez - @dmf7z
 */
library LogExpMath {
    // All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying
    // two numbers, and multiply by ONE when dividing them.

    // All arguments and return values are 18 decimal fixed point numbers.
    int256 constant ONE_18 = 1e18;

    // Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the
    // case of ln36, 36 decimals.
    int256 constant ONE_20 = 1e20;
    int256 constant ONE_36 = 1e36;

    // The domain of natural exponentiation is bound by the word size and number of decimals used.
    //
    // Because internally the result will be stored using 20 decimals, the largest possible result is
    // (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.
    // The smallest possible result is 10^(-18), which makes largest negative argument
    // ln(10^(-18)) = -41.446531673892822312.
    // We use 130.0 and -41.0 to have some safety margin.
    int256 constant MAX_NATURAL_EXPONENT = 130e18;
    int256 constant MIN_NATURAL_EXPONENT = -41e18;

    // Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point
    // 256 bit integer.
    int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;
    int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;

    uint256 constant MILD_EXPONENT_BOUND = 2 ** 254 / uint256(ONE_20);

    // 18 decimal constants
    int256 constant x0 = 128_000_000_000_000_000_000; // 2ˆ7
    int256 constant a0 = 38_877_084_059_945_950_922_200_000_000_000_000_000_000_000_000_000_000_000; // eˆ(x0) (no decimals)
    int256 constant x1 = 64_000_000_000_000_000_000; // 2ˆ6
    int256 constant a1 = 6_235_149_080_811_616_882_910_000_000; // eˆ(x1) (no decimals)

    // 20 decimal constants
    int256 constant x2 = 3_200_000_000_000_000_000_000; // 2ˆ5
    int256 constant a2 = 7_896_296_018_268_069_516_100_000_000_000_000; // eˆ(x2)
    int256 constant x3 = 1_600_000_000_000_000_000_000; // 2ˆ4
    int256 constant a3 = 888_611_052_050_787_263_676_000_000; // eˆ(x3)
    int256 constant x4 = 800_000_000_000_000_000_000; // 2ˆ3
    int256 constant a4 = 298_095_798_704_172_827_474_000; // eˆ(x4)
    int256 constant x5 = 400_000_000_000_000_000_000; // 2ˆ2
    int256 constant a5 = 5_459_815_003_314_423_907_810; // eˆ(x5)
    int256 constant x6 = 200_000_000_000_000_000_000; // 2ˆ1
    int256 constant a6 = 738_905_609_893_065_022_723; // eˆ(x6)
    int256 constant x7 = 100_000_000_000_000_000_000; // 2ˆ0
    int256 constant a7 = 271_828_182_845_904_523_536; // eˆ(x7)
    int256 constant x8 = 50_000_000_000_000_000_000; // 2ˆ-1
    int256 constant a8 = 164_872_127_070_012_814_685; // eˆ(x8)
    int256 constant x9 = 25_000_000_000_000_000_000; // 2ˆ-2
    int256 constant a9 = 128_402_541_668_774_148_407; // eˆ(x9)
    int256 constant x10 = 12_500_000_000_000_000_000; // 2ˆ-3
    int256 constant a10 = 113_314_845_306_682_631_683; // eˆ(x10)
    int256 constant x11 = 6_250_000_000_000_000_000; // 2ˆ-4
    int256 constant a11 = 106_449_445_891_785_942_956; // eˆ(x11)

    /**
     * @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.
     *
     * Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.
     */
    function pow(uint256 x, uint256 y) internal pure returns (uint256) {
        if (y == 0) {
            // We solve the 0^0 indetermination by making it equal one.
            return uint256(ONE_18);
        }

        if (x == 0) {
            return 0;
        }

        // Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to
        // arrive at that result. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means
        // x^y = exp(y * ln(x)).

        // The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.
        _require(x < 2 ** 255, Errors.X_OUT_OF_BOUNDS);
        int256 x_int256 = int256(x);

        // We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In
        // both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.

        // This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.
        _require(y < MILD_EXPONENT_BOUND, Errors.Y_OUT_OF_BOUNDS);
        int256 y_int256 = int256(y);

        int256 logx_times_y;
        if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {
            int256 ln_36_x = _ln_36(x_int256);

            // ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just
            // bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal
            // multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the
            // (downscaled) last 18 decimals.
            logx_times_y = ((ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18);
        } else {
            logx_times_y = _ln(x_int256) * y_int256;
        }
        logx_times_y /= ONE_18;

        // Finally, we compute exp(y * ln(x)) to arrive at x^y
        _require(
            MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT, Errors.PRODUCT_OUT_OF_BOUNDS
        );

        return uint256(exp(logx_times_y));
    }

    /**
     * @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.
     *
     * Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.
     */
    function exp(int256 x) internal pure returns (int256) {
        _require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, Errors.INVALID_EXPONENT);

        if (x < 0) {
            // We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it
            // fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).
            // Fixed point division requires multiplying by ONE_18.
            return ((ONE_18 * ONE_18) / exp(-x));
        }

        // First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,
        // where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7
        // because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the
        // decomposition.
        // At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this
        // decomposition, which will be lower than the smallest x_n.
        // exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.
        // We mutate x by subtracting x_n, making it the remainder of the decomposition.

        // The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause
        // intermediate overflows. Instead we store them as plain integers, with 0 decimals.
        // Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the
        // decomposition.

        // For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct
        // it and compute the accumulated product.

        int256 firstAN;
        if (x >= x0) {
            x -= x0;
            firstAN = a0;
        } else if (x >= x1) {
            x -= x1;
            firstAN = a1;
        } else {
            firstAN = 1; // One with no decimal places
        }

        // We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the
        // smaller terms.
        x *= 100;

        // `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point
        // one. Recall that fixed point multiplication requires dividing by ONE_20.
        int256 product = ONE_20;

        if (x >= x2) {
            x -= x2;
            product = (product * a2) / ONE_20;
        }
        if (x >= x3) {
            x -= x3;
            product = (product * a3) / ONE_20;
        }
        if (x >= x4) {
            x -= x4;
            product = (product * a4) / ONE_20;
        }
        if (x >= x5) {
            x -= x5;
            product = (product * a5) / ONE_20;
        }
        if (x >= x6) {
            x -= x6;
            product = (product * a6) / ONE_20;
        }
        if (x >= x7) {
            x -= x7;
            product = (product * a7) / ONE_20;
        }
        if (x >= x8) {
            x -= x8;
            product = (product * a8) / ONE_20;
        }
        if (x >= x9) {
            x -= x9;
            product = (product * a9) / ONE_20;
        }

        // x10 and x11 are unnecessary here since we have high enough precision already.

        // Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series
        // expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).

        int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.
        int256 term; // Each term in the sum, where the nth term is (x^n / n!).

        // The first term is simply x.
        term = x;
        seriesSum += term;

        // Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,
        // multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.

        term = ((term * x) / ONE_20) / 2;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 3;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 4;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 5;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 6;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 7;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 8;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 9;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 10;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 11;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 12;
        seriesSum += term;

        // 12 Taylor terms are sufficient for 18 decimal precision.

        // We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor
        // approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply
        // all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),
        // and then drop two digits to return an 18 decimal value.

        return (((product * seriesSum) / ONE_20) * firstAN) / 100;
    }

    /**
     * @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
     */
    function _ln(int256 a) private pure returns (int256) {
        if (a < ONE_18) {
            // Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less
            // than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.
            // Fixed point division requires multiplying by ONE_18.
            return (-_ln((ONE_18 * ONE_18) / a));
        }

        // First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which
        // we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,
        // ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot
        // be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.
        // At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this
        // decomposition, which will be lower than the smallest a_n.
        // ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.
        // We mutate a by subtracting a_n, making it the remainder of the decomposition.

        // For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point
        // numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by
        // ONE_18 to convert them to fixed point.
        // For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide
        // by it and compute the accumulated sum.

        int256 sum = 0;
        if (a >= a0 * ONE_18) {
            a /= a0; // Integer, not fixed point division
            sum += x0;
        }

        if (a >= a1 * ONE_18) {
            a /= a1; // Integer, not fixed point division
            sum += x1;
        }

        // All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.
        sum *= 100;
        a *= 100;

        // Because further a_n are  20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.

        if (a >= a2) {
            a = (a * ONE_20) / a2;
            sum += x2;
        }

        if (a >= a3) {
            a = (a * ONE_20) / a3;
            sum += x3;
        }

        if (a >= a4) {
            a = (a * ONE_20) / a4;
            sum += x4;
        }

        if (a >= a5) {
            a = (a * ONE_20) / a5;
            sum += x5;
        }

        if (a >= a6) {
            a = (a * ONE_20) / a6;
            sum += x6;
        }

        if (a >= a7) {
            a = (a * ONE_20) / a7;
            sum += x7;
        }

        if (a >= a8) {
            a = (a * ONE_20) / a8;
            sum += x8;
        }

        if (a >= a9) {
            a = (a * ONE_20) / a9;
            sum += x9;
        }

        if (a >= a10) {
            a = (a * ONE_20) / a10;
            sum += x10;
        }

        if (a >= a11) {
            a = (a * ONE_20) / a11;
            sum += x11;
        }

        // a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series
        // that converges rapidly for values of `a` close to one - the same one used in ln_36.
        // Let z = (a - 1) / (a + 1).
        // ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))

        // Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires
        // division by ONE_20.
        int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);
        int256 z_squared = (z * z) / ONE_20;

        // num is the numerator of the series: the z^(2 * n + 1) term
        int256 num = z;

        // seriesSum holds the accumulated sum of each term in the series, starting with the initial z
        int256 seriesSum = num;

        // In each step, the numerator is multiplied by z^2
        num = (num * z_squared) / ONE_20;
        seriesSum += num / 3;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 5;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 7;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 9;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 11;

        // 6 Taylor terms are sufficient for 36 decimal precision.

        // Finally, we multiply by 2 (non fixed point) to compute ln(remainder)
        seriesSum *= 2;

        // We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both
        // with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal
        // value.

        return (sum + seriesSum) / 100;
    }

    /**
     * @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,
     * for x close to one.
     *
     * Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.
     */
    function _ln_36(int256 x) private pure returns (int256) {
        // Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits
        // worthwhile.

        // First, we transform x to a 36 digit fixed point value.
        x *= ONE_18;

        // We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).
        // ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))

        // Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires
        // division by ONE_36.
        int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);
        int256 z_squared = (z * z) / ONE_36;

        // num is the numerator of the series: the z^(2 * n + 1) term
        int256 num = z;

        // seriesSum holds the accumulated sum of each term in the series, starting with the initial z
        int256 seriesSum = num;

        // In each step, the numerator is multiplied by z^2
        num = (num * z_squared) / ONE_36;
        seriesSum += num / 3;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 5;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 7;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 9;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 11;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 13;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 15;

        // 8 Taylor terms are sufficient for 36 decimal precision.

        // All that remains is multiplying by 2 (non fixed point).
        return seriesSum * 2;
    }
}

contract mathtest {
    function pow(uint256 base, uint256 power) public pure returns (uint256) {
        return LogExpMath.pow(base, power);
    }
}

Settings
{
  "remappings": [
    "arcadia-lending/=lib/arcadia-lending/",
    "ds-test/=lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/solmate/src/",
    "v2-periphery/=lib/v2-periphery/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"factory_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"base","type":"uint64"},{"indexed":false,"internalType":"uint16","name":"cutoffTime","type":"uint16"}],"name":"AuctionCurveParametersSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"creditor","type":"address"},{"indexed":false,"internalType":"address","name":"baseCurrency","type":"address"},{"indexed":false,"internalType":"uint128","name":"price","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"badDebt","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"initiatorReward","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"liquidationPenalty","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"remainder","type":"uint128"}],"name":"AuctionFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"creditor","type":"address"},{"indexed":false,"internalType":"address","name":"baseCurrency","type":"address"},{"indexed":false,"internalType":"uint128","name":"openDebt","type":"uint128"}],"name":"AuctionStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"minPriceMultiplier","type":"uint8"}],"name":"MinimumPriceMultiplierSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"startPriceMultiplier","type":"uint16"}],"name":"StartPriceMultiplierSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"initiatorRewardWeight","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"penaltyWeight","type":"uint8"}],"name":"WeightsSet","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"auctionInformation","outputs":[{"internalType":"uint128","name":"openDebt","type":"uint128"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"bool","name":"inAuction","type":"bool"},{"internalType":"uint80","name":"maxInitiatorFee","type":"uint80"},{"internalType":"address","name":"baseCurrency","type":"address"},{"internalType":"uint16","name":"startPriceMultiplier","type":"uint16"},{"internalType":"uint8","name":"minPriceMultiplier","type":"uint8"},{"internalType":"uint8","name":"initiatorRewardWeight","type":"uint8"},{"internalType":"uint8","name":"penaltyWeight","type":"uint8"},{"internalType":"uint16","name":"cutoffTime","type":"uint16"},{"internalType":"address","name":"originalOwner","type":"address"},{"internalType":"address","name":"trustedCreditor","type":"address"},{"internalType":"uint64","name":"base","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"base","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"buyVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"openDebt","type":"uint256"},{"internalType":"uint256","name":"priceOfVault","type":"uint256"},{"internalType":"uint88","name":"maxInitiatorFee","type":"uint88"}],"name":"calcLiquidationSettlementValues","outputs":[{"internalType":"uint256","name":"badDebt","type":"uint256"},{"internalType":"uint256","name":"liquidationInitiatorReward","type":"uint256"},{"internalType":"uint256","name":"liquidationPenalty","type":"uint256"},{"internalType":"uint256","name":"remainder","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cutoffTime","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"endAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"getPriceOfVault","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"inAuction","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initiatorRewardWeight","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minPriceMultiplier","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"penaltyWeight","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"halfLifeTime","type":"uint16"},{"internalType":"uint16","name":"cutoffTime_","type":"uint16"}],"name":"setAuctionCurveParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"minPriceMultiplier_","type":"uint8"}],"name":"setMinimumPriceMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"startPriceMultiplier_","type":"uint16"}],"name":"setStartPriceMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"initiatorRewardWeight_","type":"uint256"},{"internalType":"uint256","name":"penaltyWeight_","type":"uint256"}],"name":"setWeights","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"openDebt","type":"uint256"},{"internalType":"uint80","name":"maxInitiatorFee","type":"uint80"}],"name":"startAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startPriceMultiplier","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b5060405162002f2338038062002f238339810160408190526200003491620000c0565b600080546001600160a01b031916339081178255604051909182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b0316608052600180546000805463ffffffff19909216630501384017909255600160a01b600160f81b0319166a06f003cd4697d1631e004b60a11b179055620000f2565b600060208284031215620000d357600080fd5b81516001600160a01b0381168114620000eb57600080fd5b9392505050565b608051612e076200011c600039600081816103e101528181610b0d01526114980152612e076000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c80638da5cb5b116100ad578063d90ac52a11610071578063d90ac52a14610403578063de2e37cc14610436578063e155acf614610449578063ef6ffef21461045e578063f2fde38b1461047157600080fd5b80638da5cb5b1461022e57806396ed48e714610259578063a25225f5146103b6578063b053ad3b146103c9578063c45a0155146103dc57600080fd5b80636111fbf4116100f45780636111fbf4146101be57806362107e8d146101d357806364b22c64146101f457806378d6c03f146102075780638369c66f1461021a57600080fd5b8063044c881014610126578063147327f8146101505780632a340056146101785780635001f3b51461018c575b600080fd5b6001546101399062010000900460ff1681565b60405160ff90911681526020015b60405180910390f35b61016361015e366004612a28565b610484565b60408051928352901515602083015201610147565b60005461013990600160b01b900460ff1681565b6000546101a690600160b81b90046001600160401b031681565b6040516001600160401b039091168152602001610147565b6101d16101cc366004612a63565b6105bf565b005b6001546101e19061ffff1681565b60405161ffff9091168152602001610147565b6101d1610202366004612a96565b610838565b6101d1610215366004612acf565b610bd4565b600154610139906301000000900460ff1681565b600054610241906001600160a01b031681565b6040516001600160a01b039091168152602001610147565b610316610267366004612a28565b600260208190526000918252604090912080546001820154928201546003909201546001600160801b03821693600160801b830463ffffffff1693600160a01b80850460ff90811695600160a81b90046001600160501b0316946001600160a01b038086169584810461ffff90811696600160b01b8304861696600160b81b8404871696600160c01b85041695600160c81b90940490921693908116929081169190046001600160401b03168d565b604080516001600160801b03909e168e5263ffffffff909c1660208e01529915159a8c019a909a526001600160501b0390971660608b01526001600160a01b0395861660808b015261ffff94851660a08b015260ff93841660c08b015291831660e08a015291909116610100880152166101208601529081166101408501529091166101608301526001600160401b03166101808201526101a001610147565b6101d16103c4366004612b1d565b61115a565b6101d16103d7366004612a28565b61122c565b6102417f000000000000000000000000000000000000000000000000000000000000000081565b610416610411366004612b40565b61155d565b604080519485526020850193909352918301526060820152608001610147565b6101d1610444366004612b7e565b6115ef565b6000546101e190600160a01b900461ffff1681565b6101d161046c366004612b99565b611712565b6101d161047f366004612a28565b611805565b6001600160a01b038116600090815260026020526040812054600160a01b900460ff16806104b757506000928392509050565b6001600160a01b0383811660009081526002602081815260409283902083516101a08101855281546001600160801b0381168252600160801b810463ffffffff1693820193909352600160a01b80840460ff908116151596830196909652600160a81b9093046001600160501b031660608201526001820154808716608083015283810461ffff90811660a0840152600160b01b8204871660c0840152600160b81b8204871660e0840152600160c01b8204909616610100830152600160c81b90049094166101208501529182015484166101408401526003909101549283166101608301529091046001600160401b03166101808201526105b89061187a565b9150915091565b6000546001600160a01b031633146105f25760405162461bcd60e51b81526004016105e990612bbb565b60405180910390fd5b60788261ffff16116106465760405162461bcd60e51b815260206004820152601d60248201527f4c515f534143503a2068616c664c69666554696d6520746f6f206c6f7700000060448201526064016105e9565b6170808261ffff161061069b5760405162461bcd60e51b815260206004820152601e60248201527f4c515f534143503a2068616c664c69666554696d6520746f6f2068696768000060448201526064016105e9565b610e108161ffff16116106f05760405162461bcd60e51b815260206004820152601760248201527f4c515f534143503a206375746f666620746f6f206c6f7700000000000000000060448201526064016105e9565b61fd208161ffff16106107455760405162461bcd60e51b815260206004820152601860248201527f4c515f534143503a206375746f666620746f6f2068696768000000000000000060448201526064016105e9565b6000610777671bc16d674ec8000061076961ffff8616670de0b6b3a7640000612c0d565b6001600160401b0316611945565b61078f906a0c097ce7bc90715b34b9f160241b612c33565b90506107b96001600160401b0382166107b461ffff8516670de0b6b3a7640000612c47565b611945565b506000805467ffffffffffffffff60b81b1916600160b81b6001600160401b038416908102919091179091556001805461ffff191661ffff85169081179091556040805192835260208301919091527f7453ebdd71dd8e9666c9cca0218577083bcc4c8562d0e03ede0050e6b86920d5910160405180910390a1505050565b6000546001600160a01b031633146108625760405162461bcd60e51b81526004016105e990612bbb565b6001600160a01b0382811660009081526002602081815260409283902083516101a08101855281546001600160801b0381168252600160801b810463ffffffff1693820193909352600160a01b80840460ff9081161515968301879052600160a81b9094046001600160501b031660608301526001830154808816608084015281810461ffff90811660a0850152600160b01b8204861660c0850152600160b81b8204861660e0850152600160c01b8204909516610100840152600160c81b9004909316610120820152928101548516610140840152600301549384166101608301529092046001600160401b03166101808301526109995760405162461bcd60e51b81526020600482015260136024820152724c515f45413a204e6f7420666f722073616c6560681b60448201526064016105e9565b602081015160015463ffffffff90911642039061ffff1681116109fe5760405162461bcd60e51b815260206004820152601a60248201527f4c515f45413a2041756374696f6e206e6f74206578706972656400000000000060448201526064016105e9565b6001600160a01b0384166000908152600260205260408120805460ff60a01b1916905582516060840151829182918291610a4e916001600160801b039091169083906001600160501b031661155d565b6101608a01516101408b015160405162c15fe960e51b81526001600160a01b038f81166004830152918216602482015260448101879052606481018690526084810185905260a481018490529599509397509195509350169063182bfd209060c401600060405180830381600087803b158015610aca57600080fd5b505af1158015610ade573d6000803e3d6000fd5b5050604051630f7ac64960e41b81523060048201526001600160a01b038a811660248301528b811660448301527f000000000000000000000000000000000000000000000000000000000000000016925063f7ac64909150606401600060405180830381600087803b158015610b5357600080fd5b505af1158015610b67573d6000803e3d6000fd5b505050508561016001516001600160a01b0316886001600160a01b03167f426abe520ea0da23c5f3a60d70b96dd412f01f65eed8deb3055f916dda3ef3ee8860800151600088888888604051610bc296959493929190612c5e565b60405180910390a35050505050505050565b6001600160a01b038316600090815260026020526040902054600160a01b900460ff1615610c445760405162461bcd60e51b815260206004820152601e60248201527f4c515f53413a2041756374696f6e20616c7265616479206f6e676f696e67000060448201526064016105e9565b6001600160a01b038316600081815260026020526040808220805460ff60a01b1916600160a01b1790555163486785dd60e11b815260048101859052909182918291906390cf0bba906024016060604051808303816000875af1158015610caf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd39190612c9f565b919450925090506001600160a01b0381163314610d285760405162461bcd60e51b8152602060048201526013602482015272131457d4d04e88155b985d5d1a1bdc9a5cd959606a1b60448201526064016105e9565b8460026000886001600160a01b03166001600160a01b0316815260200190815260200160002060000160006101000a8154816001600160801b0302191690836001600160801b031602179055504260026000886001600160a01b03166001600160a01b0316815260200190815260200160002060000160106101000a81548163ffffffff021916908363ffffffff1602179055508360026000886001600160a01b03166001600160a01b0316815260200190815260200160002060000160156101000a8154816001600160501b0302191690836001600160501b031602179055508160026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600060149054906101000a900461ffff1660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160146101000a81548161ffff021916908361ffff160217905550600060169054906101000a900460ff1660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160166101000a81548160ff021916908360ff160217905550600160029054906101000a900460ff1660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160176101000a81548160ff021916908360ff160217905550600160039054906101000a900460ff1660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160186101000a81548160ff021916908360ff160217905550600160009054906101000a900461ffff1660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160196101000a81548161ffff021916908361ffff1602179055508260026000886001600160a01b03166001600160a01b0316815260200190815260200160002060020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055503360026000886001600160a01b03166001600160a01b0316815260200190815260200160002060030160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600060179054906101000a90046001600160401b031660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060030160146101000a8154816001600160401b0302191690836001600160401b03160217905550806001600160a01b0316866001600160a01b03167fea91fec3b73acb0f9c6758639395769d94948f613c930b40606a08c0bf5eb536848860405161114a9291906001600160a01b039290921682526001600160801b0316602082015260400190565b60405180910390a3505050505050565b6000546001600160a01b031633146111845760405162461bcd60e51b81526004016105e990612bbb565b605b8160ff16106111d75760405162461bcd60e51b815260206004820152601c60248201527f4c515f534d504d3a206d756c7469706c69657220746f6f20686967680000000060448201526064016105e9565b6000805460ff60b01b1916600160b01b60ff8416908102919091179091556040519081527f3e91fe161f12885d764e80ae1856102f044644a406a994790edf8e39ab8e0d4e906020015b60405180910390a150565b6001600160a01b0381811660009081526002602081815260409283902083516101a08101855281546001600160801b0381168252600160801b810463ffffffff1693820193909352600160a01b80840460ff9081161515968301879052600160a81b9094046001600160501b031660608301526001830154808816608084015281810461ffff90811660a0850152600160b01b8204861660c0850152600160b81b8204861660e0850152600160c01b8204909516610100840152600160c81b9004909316610120820152928101548516610140840152600301549384166101608301529092046001600160401b03166101808301526113635760405162461bcd60e51b81526020600482015260136024820152724c515f42563a204e6f7420666f722073616c6560681b60448201526064016105e9565b600061136e8261187a565b6001600160a01b038085166000908152600260205260409020805460ff60a01b1916905561016084015160808501519293506113b09290911690339084611abc565b6000806000806113db86600001516001600160801b03168688606001516001600160501b031661155d565b6101608a01516101408b015160405162c15fe960e51b81526001600160a01b038e81166004830152918216602482015260448101879052606481018690526084810185905260a481018490529599509397509195509350169063182bfd209060c401600060405180830381600087803b15801561145757600080fd5b505af115801561146b573d6000803e3d6000fd5b5050604051630f7ac64960e41b81523060048201523360248201526001600160a01b038a811660448301527f000000000000000000000000000000000000000000000000000000000000000016925063f7ac64909150606401600060405180830381600087803b1580156114de57600080fd5b505af11580156114f2573d6000803e3d6000fd5b505050508561016001516001600160a01b0316876001600160a01b03167f426abe520ea0da23c5f3a60d70b96dd412f01f65eed8deb3055f916dda3ef3ee8860800151888888888860405161154c96959493929190612c5e565b60405180910390a350505050505050565b60015460009060646201000090910460ff1685020481806affffffffffffffffffffff8516831161158e578261159d565b846affffffffffffffffffffff165b92508287018610156115b557858388010393506115e6565b6001546064906301000000900460ff16880204915082878703039050818111156115e1578190036115e6565b905060005b93509350935093565b6000546001600160a01b031633146116195760405162461bcd60e51b81526004016105e990612bbb565b60648161ffff161161166d5760405162461bcd60e51b815260206004820152601b60248201527f4c515f5353504d3a206d756c7469706c69657220746f6f206c6f77000000000060448201526064016105e9565b61012d8161ffff16106116c25760405162461bcd60e51b815260206004820152601c60248201527f4c515f5353504d3a206d756c7469706c69657220746f6f20686967680000000060448201526064016105e9565b6000805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527f481ae94393939cf85cea059a64ac5f8d2828428b9beb09948fa5151c6aad698690602001611221565b6000546001600160a01b0316331461173c5760405162461bcd60e51b81526004016105e990612bbb565b600b6117488284612ce1565b11156117965760405162461bcd60e51b815260206004820152601760248201527f4c515f53573a205765696768747320546f6f204869676800000000000000000060448201526064016105e9565b6001805463ffff000019166201000060ff85811691820263ff0000001916929092176301000000928516928302179092556040805192835260208301919091527faf9e67911fed86b726beb71d270a9b242c16b714f591fb7adea1b3b83c843bd8910160405180910390a15050565b6000546001600160a01b0316331461182f5760405162461bcd60e51b81526004016105e990612bbb565b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b602081015161012082015160009163ffffffff1642039061ffff168111156118ca5760648360c0015160ff1684600001516001600160801b031602816118c2576118c2612be1565b04915061193f565b80670de0b6b3a764000002905068056bc75e2d631000008360c0015160ff16670de0b6b3a7640000028460c0015160ff168560a001510361ffff1661191d8661018001516001600160401b031685611945565b020184600001516001600160801b0316028161193b5761193b612be1565b0491505b50919050565b60008160000361195e5750670de0b6b3a7640000611ab6565b8260000361196e57506000611ab6565b61197f600160ff1b84106006611b46565b826119a361199a68056bc75e2d63100000600160fe1b612c33565b84106007611b46565b826000826119c167016345785d8a0000670de0b6b3a7640000612cf4565b1280156119e657506119e3670de0b6b3a764000067016345785d8a0000612d1b565b83125b15611a4f5760006119f684611b58565b9050670de0b6b3a764000083611a0c8284612d43565b611a169190612d57565b611a209190612d87565b83611a33670de0b6b3a764000084612d87565b611a3d9190612d57565b611a479190612d1b565b915050611a66565b81611a5984611d99565b611a639190612d57565b90505b611a78670de0b6b3a764000082612d87565b9050611aa781680238fd42c5cf03ffff1913158015611aa0575068070c1cc73b00c800008213155b6008611b46565b611ab08161237f565b93505050505b92915050565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080611b3f5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016105e9565b5050505050565b81611b5457611b54816129b6565b5050565b6000611b6c670de0b6b3a764000083612d57565b91506000611b886a0c097ce7bc90715b34b9f160241b84612d1b565b6a0c097ce7bc90715b34b9f160241b611ba18186612cf4565b611bab9190612d57565b611bb59190612d87565b905060006a0c097ce7bc90715b34b9f160241b611bd28380612d57565b611bdc9190612d87565b905081806a0c097ce7bc90715b34b9f160241b611bf98483612d57565b611c039190612d87565b9150611c10600383612d87565b611c1a9082612d1b565b90506a0c097ce7bc90715b34b9f160241b611c358484612d57565b611c3f9190612d87565b9150611c4c600583612d87565b611c569082612d1b565b90506a0c097ce7bc90715b34b9f160241b611c718484612d57565b611c7b9190612d87565b9150611c88600783612d87565b611c929082612d1b565b90506a0c097ce7bc90715b34b9f160241b611cad8484612d57565b611cb79190612d87565b9150611cc4600983612d87565b611cce9082612d1b565b90506a0c097ce7bc90715b34b9f160241b611ce98484612d57565b611cf39190612d87565b9150611d00600b83612d87565b611d0a9082612d1b565b90506a0c097ce7bc90715b34b9f160241b611d258484612d57565b611d2f9190612d87565b9150611d3c600d83612d87565b611d469082612d1b565b90506a0c097ce7bc90715b34b9f160241b611d618484612d57565b611d6b9190612d87565b9150611d78600f83612d87565b611d829082612d1b565b9050611d8f816002612d57565b9695505050505050565b6000670de0b6b3a7640000821215611dd957611dd082611dc1670de0b6b3a764000080612d57565b611dcb9190612d87565b611d99565b611ab690612db5565b6000611e05670de0b6b3a7640000770195e54c5dd42177f53a27172fa9ec630262827000000000612d57565b8312611e4557611e2d770195e54c5dd42177f53a27172fa9ec63026282700000000084612d87565b9250611e426806f05b59d3b200000082612d1b565b90505b611e63670de0b6b3a76400006b1425982cf597cd205cef7380612d57565b8312611e9757611e7f6b1425982cf597cd205cef738084612d87565b9250611e946803782dace9d900000082612d1b565b90505b611ea2606482612d57565b9050611eaf606484612d57565b92506e01855144814a7ff805980ff00840008312611f0c576e01855144814a7ff805980ff0084000611eea68056bc75e2d6310000085612d57565b611ef49190612d87565b9250611f0968ad78ebc5ac6200000082612d1b565b90505b6b02df0ab5a80a22c61ab5a7008312611f61576b02df0ab5a80a22c61ab5a700611f3f68056bc75e2d6310000085612d57565b611f499190612d87565b9250611f5e6856bc75e2d63100000082612d1b565b90505b693f1fce3da636ea5cf8508312611fb257693f1fce3da636ea5cf850611f9068056bc75e2d6310000085612d57565b611f9a9190612d87565b9250611faf682b5e3af16b1880000082612d1b565b90505b690127fa27722cc06cc5e2831261200357690127fa27722cc06cc5e2611fe168056bc75e2d6310000085612d57565b611feb9190612d87565b92506120006815af1d78b58c40000082612d1b565b90505b68280e60114edb805d0383126120525768280e60114edb805d0361203068056bc75e2d6310000085612d57565b61203a9190612d87565b925061204f680ad78ebc5ac620000082612d1b565b90505b680ebc5fb4174612111083126120a157680ebc5fb4174612111061207f68056bc75e2d6310000085612d57565b6120899190612d87565b925061209e68056bc75e2d6310000082612d1b565b90505b6808f00f760a4b2db55d83126120f0576808f00f760a4b2db55d6120ce68056bc75e2d6310000085612d57565b6120d89190612d87565b92506120ed6802b5e3af16b188000082612d1b565b90505b6806f5f1775788937937831261213f576806f5f177578893793761211d68056bc75e2d6310000085612d57565b6121279190612d87565b925061213c68015af1d78b58c4000082612d1b565b90505b6806248f33704b286603831261218d576806248f33704b28660361216c68056bc75e2d6310000085612d57565b6121769190612d87565b925061218a67ad78ebc5ac62000082612d1b565b90505b6805c548670b9510e7ac83126121db576805c548670b9510e7ac6121ba68056bc75e2d6310000085612d57565b6121c49190612d87565b92506121d86756bc75e2d631000082612d1b565b90505b60006121f068056bc75e2d6310000085612d1b565b68056bc75e2d631000006122048187612cf4565b61220e9190612d57565b6122189190612d87565b9050600068056bc75e2d631000006122308380612d57565b61223a9190612d87565b9050818068056bc75e2d631000006122528483612d57565b61225c9190612d87565b9150612269600383612d87565b6122739082612d1b565b905068056bc75e2d631000006122898484612d57565b6122939190612d87565b91506122a0600583612d87565b6122aa9082612d1b565b905068056bc75e2d631000006122c08484612d57565b6122ca9190612d87565b91506122d7600783612d87565b6122e19082612d1b565b905068056bc75e2d631000006122f78484612d57565b6123019190612d87565b915061230e600983612d87565b6123189082612d1b565b905068056bc75e2d6310000061232e8484612d57565b6123389190612d87565b9150612345600b83612d87565b61234f9082612d1b565b905061235c600282612d57565b9050606461236a8287612d1b565b6123749190612d87565b979650505050505050565b60006123ae680238fd42c5cf03ffff1983121580156123a7575068070c1cc73b00c800008313155b6009611b46565b60008212156123e4576123c86123c383612db5565b61237f565b6123da670de0b6b3a764000080612d57565b611ab69190612d87565b60006806f05b59d3b2000000831261242b576124096806f05b59d3b200000084612cf4565b9250770195e54c5dd42177f53a27172fa9ec6302628270000000009050612468565b6803782dace9d900000083126124645761244e6803782dace9d900000084612cf4565b92506b1425982cf597cd205cef73809050612468565b5060015b612473606484612d57565b925068056bc75e2d6310000068ad78ebc5ac6200000084126124d4576124a268ad78ebc5ac6200000085612cf4565b935068056bc75e2d631000006124c76e01855144814a7ff805980ff008400083612d57565b6124d19190612d87565b90505b6856bc75e2d6310000008412612526576124f76856bc75e2d63100000085612cf4565b935068056bc75e2d631000006125196b02df0ab5a80a22c61ab5a70083612d57565b6125239190612d87565b90505b682b5e3af16b18800000841261257657612549682b5e3af16b1880000085612cf4565b935068056bc75e2d63100000612569693f1fce3da636ea5cf85083612d57565b6125739190612d87565b90505b6815af1d78b58c40000084126125c6576125996815af1d78b58c40000085612cf4565b935068056bc75e2d631000006125b9690127fa27722cc06cc5e283612d57565b6125c39190612d87565b90505b680ad78ebc5ac62000008412612615576125e9680ad78ebc5ac620000085612cf4565b935068056bc75e2d6310000061260868280e60114edb805d0383612d57565b6126129190612d87565b90505b68056bc75e2d6310000084126126645761263868056bc75e2d6310000085612cf4565b935068056bc75e2d63100000612657680ebc5fb4174612111083612d57565b6126619190612d87565b90505b6802b5e3af16b188000084126126b3576126876802b5e3af16b188000085612cf4565b935068056bc75e2d631000006126a66808f00f760a4b2db55d83612d57565b6126b09190612d87565b90505b68015af1d78b58c400008412612702576126d668015af1d78b58c4000085612cf4565b935068056bc75e2d631000006126f56806f5f177578893793783612d57565b6126ff9190612d87565b90505b68056bc75e2d63100000846127178183612d1b565b9150600268056bc75e2d6310000061272f8884612d57565b6127399190612d87565b6127439190612d87565b905061274f8183612d1b565b9150600368056bc75e2d631000006127678884612d57565b6127719190612d87565b61277b9190612d87565b90506127878183612d1b565b9150600468056bc75e2d6310000061279f8884612d57565b6127a99190612d87565b6127b39190612d87565b90506127bf8183612d1b565b9150600568056bc75e2d631000006127d78884612d57565b6127e19190612d87565b6127eb9190612d87565b90506127f78183612d1b565b9150600668056bc75e2d6310000061280f8884612d57565b6128199190612d87565b6128239190612d87565b905061282f8183612d1b565b9150600768056bc75e2d631000006128478884612d57565b6128519190612d87565b61285b9190612d87565b90506128678183612d1b565b9150600868056bc75e2d6310000061287f8884612d57565b6128899190612d87565b6128939190612d87565b905061289f8183612d1b565b9150600968056bc75e2d631000006128b78884612d57565b6128c19190612d87565b6128cb9190612d87565b90506128d78183612d1b565b9150600a68056bc75e2d631000006128ef8884612d57565b6128f99190612d87565b6129039190612d87565b905061290f8183612d1b565b9150600b68056bc75e2d631000006129278884612d57565b6129319190612d87565b61293b9190612d87565b90506129478183612d1b565b9150600c68056bc75e2d6310000061295f8884612d57565b6129699190612d87565b6129739190612d87565b905061297f8183612d1b565b915060648468056bc75e2d631000006129988587612d57565b6129a29190612d87565b6129ac9190612d57565b611d8f9190612d87565b6030600a820601600a820491506030600a830601600a830492506030600a8406018060101b8260081b8401016642414c230000000160c81b9250505062461bcd60e51b600052602060045260076024528060445260646000fd5b6001600160a01b0381168114612a2557600080fd5b50565b600060208284031215612a3a57600080fd5b8135612a4581612a10565b9392505050565b803561ffff81168114612a5e57600080fd5b919050565b60008060408385031215612a7657600080fd5b612a7f83612a4c565b9150612a8d60208401612a4c565b90509250929050565b60008060408385031215612aa957600080fd5b8235612ab481612a10565b91506020830135612ac481612a10565b809150509250929050565b600080600060608486031215612ae457600080fd5b8335612aef81612a10565b92506020840135915060408401356001600160501b0381168114612b1257600080fd5b809150509250925092565b600060208284031215612b2f57600080fd5b813560ff81168114612a4557600080fd5b600080600060608486031215612b5557600080fd5b833592506020840135915060408401356affffffffffffffffffffff81168114612b1257600080fd5b600060208284031215612b9057600080fd5b612a4582612a4c565b60008060408385031215612bac57600080fd5b50508035926020909101359150565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001600160401b0380841680612c2757612c27612be1565b92169190910492915050565b600082612c4257612c42612be1565b500490565b8082028115828204841417611ab657611ab6612bf7565b6001600160a01b039690961686526001600160801b03948516602087015292841660408601529083166060850152821660808401521660a082015260c00190565b600080600060608486031215612cb457600080fd5b8351612cbf81612a10565b6020850151909350612cd081612a10565b6040850151909250612b1281612a10565b80820180821115611ab657611ab6612bf7565b8181036000831280158383131683831282161715612d1457612d14612bf7565b5092915050565b8082018281126000831280158216821582161715612d3b57612d3b612bf7565b505092915050565b600082612d5257612d52612be1565b500790565b80820260008212600160ff1b84141615612d7357612d73612bf7565b8181058314821517611ab657611ab6612bf7565b600082612d9657612d96612be1565b600160ff1b821460001984141615612db057612db0612bf7565b500590565b6000600160ff1b8201612dca57612dca612bf7565b506000039056fea26469706673582212207d364c5dac064287aaa74fdaa077a67bd5942915cc86f745690b0e036e2abc8164736f6c6343000811003300000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101215760003560e01c80638da5cb5b116100ad578063d90ac52a11610071578063d90ac52a14610403578063de2e37cc14610436578063e155acf614610449578063ef6ffef21461045e578063f2fde38b1461047157600080fd5b80638da5cb5b1461022e57806396ed48e714610259578063a25225f5146103b6578063b053ad3b146103c9578063c45a0155146103dc57600080fd5b80636111fbf4116100f45780636111fbf4146101be57806362107e8d146101d357806364b22c64146101f457806378d6c03f146102075780638369c66f1461021a57600080fd5b8063044c881014610126578063147327f8146101505780632a340056146101785780635001f3b51461018c575b600080fd5b6001546101399062010000900460ff1681565b60405160ff90911681526020015b60405180910390f35b61016361015e366004612a28565b610484565b60408051928352901515602083015201610147565b60005461013990600160b01b900460ff1681565b6000546101a690600160b81b90046001600160401b031681565b6040516001600160401b039091168152602001610147565b6101d16101cc366004612a63565b6105bf565b005b6001546101e19061ffff1681565b60405161ffff9091168152602001610147565b6101d1610202366004612a96565b610838565b6101d1610215366004612acf565b610bd4565b600154610139906301000000900460ff1681565b600054610241906001600160a01b031681565b6040516001600160a01b039091168152602001610147565b610316610267366004612a28565b600260208190526000918252604090912080546001820154928201546003909201546001600160801b03821693600160801b830463ffffffff1693600160a01b80850460ff90811695600160a81b90046001600160501b0316946001600160a01b038086169584810461ffff90811696600160b01b8304861696600160b81b8404871696600160c01b85041695600160c81b90940490921693908116929081169190046001600160401b03168d565b604080516001600160801b03909e168e5263ffffffff909c1660208e01529915159a8c019a909a526001600160501b0390971660608b01526001600160a01b0395861660808b015261ffff94851660a08b015260ff93841660c08b015291831660e08a015291909116610100880152166101208601529081166101408501529091166101608301526001600160401b03166101808201526101a001610147565b6101d16103c4366004612b1d565b61115a565b6101d16103d7366004612a28565b61122c565b6102417f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb81565b610416610411366004612b40565b61155d565b604080519485526020850193909352918301526060820152608001610147565b6101d1610444366004612b7e565b6115ef565b6000546101e190600160a01b900461ffff1681565b6101d161046c366004612b99565b611712565b6101d161047f366004612a28565b611805565b6001600160a01b038116600090815260026020526040812054600160a01b900460ff16806104b757506000928392509050565b6001600160a01b0383811660009081526002602081815260409283902083516101a08101855281546001600160801b0381168252600160801b810463ffffffff1693820193909352600160a01b80840460ff908116151596830196909652600160a81b9093046001600160501b031660608201526001820154808716608083015283810461ffff90811660a0840152600160b01b8204871660c0840152600160b81b8204871660e0840152600160c01b8204909616610100830152600160c81b90049094166101208501529182015484166101408401526003909101549283166101608301529091046001600160401b03166101808201526105b89061187a565b9150915091565b6000546001600160a01b031633146105f25760405162461bcd60e51b81526004016105e990612bbb565b60405180910390fd5b60788261ffff16116106465760405162461bcd60e51b815260206004820152601d60248201527f4c515f534143503a2068616c664c69666554696d6520746f6f206c6f7700000060448201526064016105e9565b6170808261ffff161061069b5760405162461bcd60e51b815260206004820152601e60248201527f4c515f534143503a2068616c664c69666554696d6520746f6f2068696768000060448201526064016105e9565b610e108161ffff16116106f05760405162461bcd60e51b815260206004820152601760248201527f4c515f534143503a206375746f666620746f6f206c6f7700000000000000000060448201526064016105e9565b61fd208161ffff16106107455760405162461bcd60e51b815260206004820152601860248201527f4c515f534143503a206375746f666620746f6f2068696768000000000000000060448201526064016105e9565b6000610777671bc16d674ec8000061076961ffff8616670de0b6b3a7640000612c0d565b6001600160401b0316611945565b61078f906a0c097ce7bc90715b34b9f160241b612c33565b90506107b96001600160401b0382166107b461ffff8516670de0b6b3a7640000612c47565b611945565b506000805467ffffffffffffffff60b81b1916600160b81b6001600160401b038416908102919091179091556001805461ffff191661ffff85169081179091556040805192835260208301919091527f7453ebdd71dd8e9666c9cca0218577083bcc4c8562d0e03ede0050e6b86920d5910160405180910390a1505050565b6000546001600160a01b031633146108625760405162461bcd60e51b81526004016105e990612bbb565b6001600160a01b0382811660009081526002602081815260409283902083516101a08101855281546001600160801b0381168252600160801b810463ffffffff1693820193909352600160a01b80840460ff9081161515968301879052600160a81b9094046001600160501b031660608301526001830154808816608084015281810461ffff90811660a0850152600160b01b8204861660c0850152600160b81b8204861660e0850152600160c01b8204909516610100840152600160c81b9004909316610120820152928101548516610140840152600301549384166101608301529092046001600160401b03166101808301526109995760405162461bcd60e51b81526020600482015260136024820152724c515f45413a204e6f7420666f722073616c6560681b60448201526064016105e9565b602081015160015463ffffffff90911642039061ffff1681116109fe5760405162461bcd60e51b815260206004820152601a60248201527f4c515f45413a2041756374696f6e206e6f74206578706972656400000000000060448201526064016105e9565b6001600160a01b0384166000908152600260205260408120805460ff60a01b1916905582516060840151829182918291610a4e916001600160801b039091169083906001600160501b031661155d565b6101608a01516101408b015160405162c15fe960e51b81526001600160a01b038f81166004830152918216602482015260448101879052606481018690526084810185905260a481018490529599509397509195509350169063182bfd209060c401600060405180830381600087803b158015610aca57600080fd5b505af1158015610ade573d6000803e3d6000fd5b5050604051630f7ac64960e41b81523060048201526001600160a01b038a811660248301528b811660448301527f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb16925063f7ac64909150606401600060405180830381600087803b158015610b5357600080fd5b505af1158015610b67573d6000803e3d6000fd5b505050508561016001516001600160a01b0316886001600160a01b03167f426abe520ea0da23c5f3a60d70b96dd412f01f65eed8deb3055f916dda3ef3ee8860800151600088888888604051610bc296959493929190612c5e565b60405180910390a35050505050505050565b6001600160a01b038316600090815260026020526040902054600160a01b900460ff1615610c445760405162461bcd60e51b815260206004820152601e60248201527f4c515f53413a2041756374696f6e20616c7265616479206f6e676f696e67000060448201526064016105e9565b6001600160a01b038316600081815260026020526040808220805460ff60a01b1916600160a01b1790555163486785dd60e11b815260048101859052909182918291906390cf0bba906024016060604051808303816000875af1158015610caf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd39190612c9f565b919450925090506001600160a01b0381163314610d285760405162461bcd60e51b8152602060048201526013602482015272131457d4d04e88155b985d5d1a1bdc9a5cd959606a1b60448201526064016105e9565b8460026000886001600160a01b03166001600160a01b0316815260200190815260200160002060000160006101000a8154816001600160801b0302191690836001600160801b031602179055504260026000886001600160a01b03166001600160a01b0316815260200190815260200160002060000160106101000a81548163ffffffff021916908363ffffffff1602179055508360026000886001600160a01b03166001600160a01b0316815260200190815260200160002060000160156101000a8154816001600160501b0302191690836001600160501b031602179055508160026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600060149054906101000a900461ffff1660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160146101000a81548161ffff021916908361ffff160217905550600060169054906101000a900460ff1660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160166101000a81548160ff021916908360ff160217905550600160029054906101000a900460ff1660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160176101000a81548160ff021916908360ff160217905550600160039054906101000a900460ff1660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160186101000a81548160ff021916908360ff160217905550600160009054906101000a900461ffff1660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060010160196101000a81548161ffff021916908361ffff1602179055508260026000886001600160a01b03166001600160a01b0316815260200190815260200160002060020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055503360026000886001600160a01b03166001600160a01b0316815260200190815260200160002060030160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600060179054906101000a90046001600160401b031660026000886001600160a01b03166001600160a01b0316815260200190815260200160002060030160146101000a8154816001600160401b0302191690836001600160401b03160217905550806001600160a01b0316866001600160a01b03167fea91fec3b73acb0f9c6758639395769d94948f613c930b40606a08c0bf5eb536848860405161114a9291906001600160a01b039290921682526001600160801b0316602082015260400190565b60405180910390a3505050505050565b6000546001600160a01b031633146111845760405162461bcd60e51b81526004016105e990612bbb565b605b8160ff16106111d75760405162461bcd60e51b815260206004820152601c60248201527f4c515f534d504d3a206d756c7469706c69657220746f6f20686967680000000060448201526064016105e9565b6000805460ff60b01b1916600160b01b60ff8416908102919091179091556040519081527f3e91fe161f12885d764e80ae1856102f044644a406a994790edf8e39ab8e0d4e906020015b60405180910390a150565b6001600160a01b0381811660009081526002602081815260409283902083516101a08101855281546001600160801b0381168252600160801b810463ffffffff1693820193909352600160a01b80840460ff9081161515968301879052600160a81b9094046001600160501b031660608301526001830154808816608084015281810461ffff90811660a0850152600160b01b8204861660c0850152600160b81b8204861660e0850152600160c01b8204909516610100840152600160c81b9004909316610120820152928101548516610140840152600301549384166101608301529092046001600160401b03166101808301526113635760405162461bcd60e51b81526020600482015260136024820152724c515f42563a204e6f7420666f722073616c6560681b60448201526064016105e9565b600061136e8261187a565b6001600160a01b038085166000908152600260205260409020805460ff60a01b1916905561016084015160808501519293506113b09290911690339084611abc565b6000806000806113db86600001516001600160801b03168688606001516001600160501b031661155d565b6101608a01516101408b015160405162c15fe960e51b81526001600160a01b038e81166004830152918216602482015260448101879052606481018690526084810185905260a481018490529599509397509195509350169063182bfd209060c401600060405180830381600087803b15801561145757600080fd5b505af115801561146b573d6000803e3d6000fd5b5050604051630f7ac64960e41b81523060048201523360248201526001600160a01b038a811660448301527f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb16925063f7ac64909150606401600060405180830381600087803b1580156114de57600080fd5b505af11580156114f2573d6000803e3d6000fd5b505050508561016001516001600160a01b0316876001600160a01b03167f426abe520ea0da23c5f3a60d70b96dd412f01f65eed8deb3055f916dda3ef3ee8860800151888888888860405161154c96959493929190612c5e565b60405180910390a350505050505050565b60015460009060646201000090910460ff1685020481806affffffffffffffffffffff8516831161158e578261159d565b846affffffffffffffffffffff165b92508287018610156115b557858388010393506115e6565b6001546064906301000000900460ff16880204915082878703039050818111156115e1578190036115e6565b905060005b93509350935093565b6000546001600160a01b031633146116195760405162461bcd60e51b81526004016105e990612bbb565b60648161ffff161161166d5760405162461bcd60e51b815260206004820152601b60248201527f4c515f5353504d3a206d756c7469706c69657220746f6f206c6f77000000000060448201526064016105e9565b61012d8161ffff16106116c25760405162461bcd60e51b815260206004820152601c60248201527f4c515f5353504d3a206d756c7469706c69657220746f6f20686967680000000060448201526064016105e9565b6000805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527f481ae94393939cf85cea059a64ac5f8d2828428b9beb09948fa5151c6aad698690602001611221565b6000546001600160a01b0316331461173c5760405162461bcd60e51b81526004016105e990612bbb565b600b6117488284612ce1565b11156117965760405162461bcd60e51b815260206004820152601760248201527f4c515f53573a205765696768747320546f6f204869676800000000000000000060448201526064016105e9565b6001805463ffff000019166201000060ff85811691820263ff0000001916929092176301000000928516928302179092556040805192835260208301919091527faf9e67911fed86b726beb71d270a9b242c16b714f591fb7adea1b3b83c843bd8910160405180910390a15050565b6000546001600160a01b0316331461182f5760405162461bcd60e51b81526004016105e990612bbb565b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b602081015161012082015160009163ffffffff1642039061ffff168111156118ca5760648360c0015160ff1684600001516001600160801b031602816118c2576118c2612be1565b04915061193f565b80670de0b6b3a764000002905068056bc75e2d631000008360c0015160ff16670de0b6b3a7640000028460c0015160ff168560a001510361ffff1661191d8661018001516001600160401b031685611945565b020184600001516001600160801b0316028161193b5761193b612be1565b0491505b50919050565b60008160000361195e5750670de0b6b3a7640000611ab6565b8260000361196e57506000611ab6565b61197f600160ff1b84106006611b46565b826119a361199a68056bc75e2d63100000600160fe1b612c33565b84106007611b46565b826000826119c167016345785d8a0000670de0b6b3a7640000612cf4565b1280156119e657506119e3670de0b6b3a764000067016345785d8a0000612d1b565b83125b15611a4f5760006119f684611b58565b9050670de0b6b3a764000083611a0c8284612d43565b611a169190612d57565b611a209190612d87565b83611a33670de0b6b3a764000084612d87565b611a3d9190612d57565b611a479190612d1b565b915050611a66565b81611a5984611d99565b611a639190612d57565b90505b611a78670de0b6b3a764000082612d87565b9050611aa781680238fd42c5cf03ffff1913158015611aa0575068070c1cc73b00c800008213155b6008611b46565b611ab08161237f565b93505050505b92915050565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080611b3f5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016105e9565b5050505050565b81611b5457611b54816129b6565b5050565b6000611b6c670de0b6b3a764000083612d57565b91506000611b886a0c097ce7bc90715b34b9f160241b84612d1b565b6a0c097ce7bc90715b34b9f160241b611ba18186612cf4565b611bab9190612d57565b611bb59190612d87565b905060006a0c097ce7bc90715b34b9f160241b611bd28380612d57565b611bdc9190612d87565b905081806a0c097ce7bc90715b34b9f160241b611bf98483612d57565b611c039190612d87565b9150611c10600383612d87565b611c1a9082612d1b565b90506a0c097ce7bc90715b34b9f160241b611c358484612d57565b611c3f9190612d87565b9150611c4c600583612d87565b611c569082612d1b565b90506a0c097ce7bc90715b34b9f160241b611c718484612d57565b611c7b9190612d87565b9150611c88600783612d87565b611c929082612d1b565b90506a0c097ce7bc90715b34b9f160241b611cad8484612d57565b611cb79190612d87565b9150611cc4600983612d87565b611cce9082612d1b565b90506a0c097ce7bc90715b34b9f160241b611ce98484612d57565b611cf39190612d87565b9150611d00600b83612d87565b611d0a9082612d1b565b90506a0c097ce7bc90715b34b9f160241b611d258484612d57565b611d2f9190612d87565b9150611d3c600d83612d87565b611d469082612d1b565b90506a0c097ce7bc90715b34b9f160241b611d618484612d57565b611d6b9190612d87565b9150611d78600f83612d87565b611d829082612d1b565b9050611d8f816002612d57565b9695505050505050565b6000670de0b6b3a7640000821215611dd957611dd082611dc1670de0b6b3a764000080612d57565b611dcb9190612d87565b611d99565b611ab690612db5565b6000611e05670de0b6b3a7640000770195e54c5dd42177f53a27172fa9ec630262827000000000612d57565b8312611e4557611e2d770195e54c5dd42177f53a27172fa9ec63026282700000000084612d87565b9250611e426806f05b59d3b200000082612d1b565b90505b611e63670de0b6b3a76400006b1425982cf597cd205cef7380612d57565b8312611e9757611e7f6b1425982cf597cd205cef738084612d87565b9250611e946803782dace9d900000082612d1b565b90505b611ea2606482612d57565b9050611eaf606484612d57565b92506e01855144814a7ff805980ff00840008312611f0c576e01855144814a7ff805980ff0084000611eea68056bc75e2d6310000085612d57565b611ef49190612d87565b9250611f0968ad78ebc5ac6200000082612d1b565b90505b6b02df0ab5a80a22c61ab5a7008312611f61576b02df0ab5a80a22c61ab5a700611f3f68056bc75e2d6310000085612d57565b611f499190612d87565b9250611f5e6856bc75e2d63100000082612d1b565b90505b693f1fce3da636ea5cf8508312611fb257693f1fce3da636ea5cf850611f9068056bc75e2d6310000085612d57565b611f9a9190612d87565b9250611faf682b5e3af16b1880000082612d1b565b90505b690127fa27722cc06cc5e2831261200357690127fa27722cc06cc5e2611fe168056bc75e2d6310000085612d57565b611feb9190612d87565b92506120006815af1d78b58c40000082612d1b565b90505b68280e60114edb805d0383126120525768280e60114edb805d0361203068056bc75e2d6310000085612d57565b61203a9190612d87565b925061204f680ad78ebc5ac620000082612d1b565b90505b680ebc5fb4174612111083126120a157680ebc5fb4174612111061207f68056bc75e2d6310000085612d57565b6120899190612d87565b925061209e68056bc75e2d6310000082612d1b565b90505b6808f00f760a4b2db55d83126120f0576808f00f760a4b2db55d6120ce68056bc75e2d6310000085612d57565b6120d89190612d87565b92506120ed6802b5e3af16b188000082612d1b565b90505b6806f5f1775788937937831261213f576806f5f177578893793761211d68056bc75e2d6310000085612d57565b6121279190612d87565b925061213c68015af1d78b58c4000082612d1b565b90505b6806248f33704b286603831261218d576806248f33704b28660361216c68056bc75e2d6310000085612d57565b6121769190612d87565b925061218a67ad78ebc5ac62000082612d1b565b90505b6805c548670b9510e7ac83126121db576805c548670b9510e7ac6121ba68056bc75e2d6310000085612d57565b6121c49190612d87565b92506121d86756bc75e2d631000082612d1b565b90505b60006121f068056bc75e2d6310000085612d1b565b68056bc75e2d631000006122048187612cf4565b61220e9190612d57565b6122189190612d87565b9050600068056bc75e2d631000006122308380612d57565b61223a9190612d87565b9050818068056bc75e2d631000006122528483612d57565b61225c9190612d87565b9150612269600383612d87565b6122739082612d1b565b905068056bc75e2d631000006122898484612d57565b6122939190612d87565b91506122a0600583612d87565b6122aa9082612d1b565b905068056bc75e2d631000006122c08484612d57565b6122ca9190612d87565b91506122d7600783612d87565b6122e19082612d1b565b905068056bc75e2d631000006122f78484612d57565b6123019190612d87565b915061230e600983612d87565b6123189082612d1b565b905068056bc75e2d6310000061232e8484612d57565b6123389190612d87565b9150612345600b83612d87565b61234f9082612d1b565b905061235c600282612d57565b9050606461236a8287612d1b565b6123749190612d87565b979650505050505050565b60006123ae680238fd42c5cf03ffff1983121580156123a7575068070c1cc73b00c800008313155b6009611b46565b60008212156123e4576123c86123c383612db5565b61237f565b6123da670de0b6b3a764000080612d57565b611ab69190612d87565b60006806f05b59d3b2000000831261242b576124096806f05b59d3b200000084612cf4565b9250770195e54c5dd42177f53a27172fa9ec6302628270000000009050612468565b6803782dace9d900000083126124645761244e6803782dace9d900000084612cf4565b92506b1425982cf597cd205cef73809050612468565b5060015b612473606484612d57565b925068056bc75e2d6310000068ad78ebc5ac6200000084126124d4576124a268ad78ebc5ac6200000085612cf4565b935068056bc75e2d631000006124c76e01855144814a7ff805980ff008400083612d57565b6124d19190612d87565b90505b6856bc75e2d6310000008412612526576124f76856bc75e2d63100000085612cf4565b935068056bc75e2d631000006125196b02df0ab5a80a22c61ab5a70083612d57565b6125239190612d87565b90505b682b5e3af16b18800000841261257657612549682b5e3af16b1880000085612cf4565b935068056bc75e2d63100000612569693f1fce3da636ea5cf85083612d57565b6125739190612d87565b90505b6815af1d78b58c40000084126125c6576125996815af1d78b58c40000085612cf4565b935068056bc75e2d631000006125b9690127fa27722cc06cc5e283612d57565b6125c39190612d87565b90505b680ad78ebc5ac62000008412612615576125e9680ad78ebc5ac620000085612cf4565b935068056bc75e2d6310000061260868280e60114edb805d0383612d57565b6126129190612d87565b90505b68056bc75e2d6310000084126126645761263868056bc75e2d6310000085612cf4565b935068056bc75e2d63100000612657680ebc5fb4174612111083612d57565b6126619190612d87565b90505b6802b5e3af16b188000084126126b3576126876802b5e3af16b188000085612cf4565b935068056bc75e2d631000006126a66808f00f760a4b2db55d83612d57565b6126b09190612d87565b90505b68015af1d78b58c400008412612702576126d668015af1d78b58c4000085612cf4565b935068056bc75e2d631000006126f56806f5f177578893793783612d57565b6126ff9190612d87565b90505b68056bc75e2d63100000846127178183612d1b565b9150600268056bc75e2d6310000061272f8884612d57565b6127399190612d87565b6127439190612d87565b905061274f8183612d1b565b9150600368056bc75e2d631000006127678884612d57565b6127719190612d87565b61277b9190612d87565b90506127878183612d1b565b9150600468056bc75e2d6310000061279f8884612d57565b6127a99190612d87565b6127b39190612d87565b90506127bf8183612d1b565b9150600568056bc75e2d631000006127d78884612d57565b6127e19190612d87565b6127eb9190612d87565b90506127f78183612d1b565b9150600668056bc75e2d6310000061280f8884612d57565b6128199190612d87565b6128239190612d87565b905061282f8183612d1b565b9150600768056bc75e2d631000006128478884612d57565b6128519190612d87565b61285b9190612d87565b90506128678183612d1b565b9150600868056bc75e2d6310000061287f8884612d57565b6128899190612d87565b6128939190612d87565b905061289f8183612d1b565b9150600968056bc75e2d631000006128b78884612d57565b6128c19190612d87565b6128cb9190612d87565b90506128d78183612d1b565b9150600a68056bc75e2d631000006128ef8884612d57565b6128f99190612d87565b6129039190612d87565b905061290f8183612d1b565b9150600b68056bc75e2d631000006129278884612d57565b6129319190612d87565b61293b9190612d87565b90506129478183612d1b565b9150600c68056bc75e2d6310000061295f8884612d57565b6129699190612d87565b6129739190612d87565b905061297f8183612d1b565b915060648468056bc75e2d631000006129988587612d57565b6129a29190612d87565b6129ac9190612d57565b611d8f9190612d87565b6030600a820601600a820491506030600a830601600a830492506030600a8406018060101b8260081b8401016642414c230000000160c81b9250505062461bcd60e51b600052602060045260076024528060445260646000fd5b6001600160a01b0381168114612a2557600080fd5b50565b600060208284031215612a3a57600080fd5b8135612a4581612a10565b9392505050565b803561ffff81168114612a5e57600080fd5b919050565b60008060408385031215612a7657600080fd5b612a7f83612a4c565b9150612a8d60208401612a4c565b90509250929050565b60008060408385031215612aa957600080fd5b8235612ab481612a10565b91506020830135612ac481612a10565b809150509250929050565b600080600060608486031215612ae457600080fd5b8335612aef81612a10565b92506020840135915060408401356001600160501b0381168114612b1257600080fd5b809150509250925092565b600060208284031215612b2f57600080fd5b813560ff81168114612a4557600080fd5b600080600060608486031215612b5557600080fd5b833592506020840135915060408401356affffffffffffffffffffff81168114612b1257600080fd5b600060208284031215612b9057600080fd5b612a4582612a4c565b60008060408385031215612bac57600080fd5b50508035926020909101359150565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001600160401b0380841680612c2757612c27612be1565b92169190910492915050565b600082612c4257612c42612be1565b500490565b8082028115828204841417611ab657611ab6612bf7565b6001600160a01b039690961686526001600160801b03948516602087015292841660408601529083166060850152821660808401521660a082015260c00190565b600080600060608486031215612cb457600080fd5b8351612cbf81612a10565b6020850151909350612cd081612a10565b6040850151909250612b1281612a10565b80820180821115611ab657611ab6612bf7565b8181036000831280158383131683831282161715612d1457612d14612bf7565b5092915050565b8082018281126000831280158216821582161715612d3b57612d3b612bf7565b505092915050565b600082612d5257612d52612be1565b500790565b80820260008212600160ff1b84141615612d7357612d73612bf7565b8181058314821517611ab657611ab6612bf7565b600082612d9657612d96612be1565b600160ff1b821460001984141615612db057612db0612bf7565b500590565b6000600160ff1b8201612dca57612dca612bf7565b506000039056fea26469706673582212207d364c5dac064287aaa74fdaa077a67bd5942915cc86f745690b0e036e2abc8164736f6c63430008110033

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

00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb

-----Decoded View---------------
Arg [0] : factory_ (address): 0x00CB53780Ea58503D3059FC02dDd596D0Be926cB

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

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