ETH Price: $2,096.78 (-10.66%)

Contract

0x1fA408992e74A42D1787E28b880C451452E8C958
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

4 Internal Transactions found.

Latest 4 internal transactions

Advanced mode:
Parent Transaction Hash Block
From
To
218824052025-02-19 19:08:3512 days ago1739992115
0x1fA40899...452E8C958
 Contract Creation0 ETH
217722502025-02-04 9:29:4727 days ago1738661387
0x1fA40899...452E8C958
 Contract Creation0 ETH
217722502025-02-04 9:29:4727 days ago1738661387
0x1fA40899...452E8C958
 Contract Creation0 ETH
217722502025-02-04 9:29:4727 days ago1738661387
0x1fA40899...452E8C958
 Contract Creation0 ETH
Loading...
Loading

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

Contract Name:
CometFactoryWithExtendedAssetList

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion
File 1 of 12 : CometFactoryWithExtendedAssetList.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometWithExtendedAssetList.sol";
import "./CometConfiguration.sol";

contract CometFactoryWithExtendedAssetList is CometConfiguration {
    function clone(Configuration calldata config) external returns (address) {
        return address(new CometWithExtendedAssetList(config));
    }
}

File 2 of 12 : CometConfiguration.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title Compound's Comet Configuration Interface
 * @author Compound
 */
contract CometConfiguration {
    struct ExtConfiguration {
        bytes32 name32;
        bytes32 symbol32;
    }

    struct Configuration {
        address governor;
        address pauseGuardian;
        address baseToken;
        address baseTokenPriceFeed;
        address extensionDelegate;

        uint64 supplyKink;
        uint64 supplyPerYearInterestRateSlopeLow;
        uint64 supplyPerYearInterestRateSlopeHigh;
        uint64 supplyPerYearInterestRateBase;
        uint64 borrowKink;
        uint64 borrowPerYearInterestRateSlopeLow;
        uint64 borrowPerYearInterestRateSlopeHigh;
        uint64 borrowPerYearInterestRateBase;
        uint64 storeFrontPriceFactor;
        uint64 trackingIndexScale;
        uint64 baseTrackingSupplySpeed;
        uint64 baseTrackingBorrowSpeed;
        uint104 baseMinForRewards;
        uint104 baseBorrowMin;
        uint104 targetReserves;

        AssetConfig[] assetConfigs;
    }

    struct AssetConfig {
        address asset;
        address priceFeed;
        uint8 decimals;
        uint64 borrowCollateralFactor;
        uint64 liquidateCollateralFactor;
        uint64 liquidationFactor;
        uint128 supplyCap;
    }
}

File 3 of 12 : CometCore.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometConfiguration.sol";
import "./CometStorage.sol";
import "./CometMath.sol";

abstract contract CometCore is CometConfiguration, CometStorage, CometMath {
    struct AssetInfo {
        uint8 offset;
        address asset;
        address priceFeed;
        uint64 scale;
        uint64 borrowCollateralFactor;
        uint64 liquidateCollateralFactor;
        uint64 liquidationFactor;
        uint128 supplyCap;
    }

    /** Internal constants **/

    /// @dev The max number of assets this contract is hardcoded to support
    ///  Do not change this variable without updating all the fields throughout the contract,
    //    including the size of UserBasic.assetsIn and corresponding integer conversions.
    uint8 internal constant MAX_ASSETS = 15;

    /// @dev The max number of decimals base token can have
    ///  Note this cannot just be increased arbitrarily.
    uint8 internal constant MAX_BASE_DECIMALS = 18;

    /// @dev The max value for a collateral factor (1)
    uint64 internal constant MAX_COLLATERAL_FACTOR = FACTOR_SCALE;

    /// @dev Offsets for specific actions in the pause flag bit array
    uint8 internal constant PAUSE_SUPPLY_OFFSET = 0;
    uint8 internal constant PAUSE_TRANSFER_OFFSET = 1;
    uint8 internal constant PAUSE_WITHDRAW_OFFSET = 2;
    uint8 internal constant PAUSE_ABSORB_OFFSET = 3;
    uint8 internal constant PAUSE_BUY_OFFSET = 4;

    /// @dev The decimals required for a price feed
    uint8 internal constant PRICE_FEED_DECIMALS = 8;

    /// @dev 365 days * 24 hours * 60 minutes * 60 seconds
    uint64 internal constant SECONDS_PER_YEAR = 31_536_000;

    /// @dev The scale for base tracking accrual
    uint64 internal constant BASE_ACCRUAL_SCALE = 1e6;

    /// @dev The scale for base index (depends on time/rate scales, not base token)
    uint64 internal constant BASE_INDEX_SCALE = 1e15;

    /// @dev The scale for prices (in USD)
    uint64 internal constant PRICE_SCALE = uint64(10 ** PRICE_FEED_DECIMALS);

    /// @dev The scale for factors
    uint64 internal constant FACTOR_SCALE = 1e18;

    /// @dev The storage slot for reentrancy guard flags
    bytes32 internal constant REENTRANCY_GUARD_FLAG_SLOT = bytes32(keccak256("comet.reentrancy.guard"));

    /// @dev The reentrancy guard statuses
    uint256 internal constant REENTRANCY_GUARD_NOT_ENTERED = 0;
    uint256 internal constant REENTRANCY_GUARD_ENTERED = 1;

    /**
     * @notice Determine if the manager has permission to act on behalf of the owner
     * @param owner The owner account
     * @param manager The manager account
     * @return Whether or not the manager has permission
     */
    function hasPermission(address owner, address manager) public view returns (bool) {
        return owner == manager || isAllowed[owner][manager];
    }

    /**
     * @dev The positive present supply balance if positive or the negative borrow balance if negative
     */
    function presentValue(int104 principalValue_) internal view returns (int256) {
        if (principalValue_ >= 0) {
            return signed256(presentValueSupply(baseSupplyIndex, uint104(principalValue_)));
        } else {
            return -signed256(presentValueBorrow(baseBorrowIndex, uint104(-principalValue_)));
        }
    }

    /**
     * @dev The principal amount projected forward by the supply index
     */
    function presentValueSupply(uint64 baseSupplyIndex_, uint104 principalValue_) internal pure returns (uint256) {
        return uint256(principalValue_) * baseSupplyIndex_ / BASE_INDEX_SCALE;
    }

    /**
     * @dev The principal amount projected forward by the borrow index
     */
    function presentValueBorrow(uint64 baseBorrowIndex_, uint104 principalValue_) internal pure returns (uint256) {
        return uint256(principalValue_) * baseBorrowIndex_ / BASE_INDEX_SCALE;
    }

    /**
     * @dev The positive principal if positive or the negative principal if negative
     */
    function principalValue(int256 presentValue_) internal view returns (int104) {
        if (presentValue_ >= 0) {
            return signed104(principalValueSupply(baseSupplyIndex, uint256(presentValue_)));
        } else {
            return -signed104(principalValueBorrow(baseBorrowIndex, uint256(-presentValue_)));
        }
    }

    /**
     * @dev The present value projected backward by the supply index (rounded down)
     *  Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals.
     */
    function principalValueSupply(uint64 baseSupplyIndex_, uint256 presentValue_) internal pure returns (uint104) {
        return safe104((presentValue_ * BASE_INDEX_SCALE) / baseSupplyIndex_);
    }

    /**
     * @dev The present value projected backward by the borrow index (rounded up)
     *  Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals.
     */
    function principalValueBorrow(uint64 baseBorrowIndex_, uint256 presentValue_) internal pure returns (uint104) {
        return safe104((presentValue_ * BASE_INDEX_SCALE + baseBorrowIndex_ - 1) / baseBorrowIndex_);
    }
}

File 4 of 12 : CometMainInterface.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometCore.sol";

/**
 * @title Compound's Comet Main Interface (without Ext)
 * @notice An efficient monolithic money market protocol
 * @author Compound
 */
abstract contract CometMainInterface is CometCore {
    error Absurd();
    error AlreadyInitialized();
    error BadAsset();
    error BadDecimals();
    error BadDiscount();
    error BadMinimum();
    error BadPrice();
    error BorrowTooSmall();
    error BorrowCFTooLarge();
    error InsufficientReserves();
    error LiquidateCFTooLarge();
    error NoSelfTransfer();
    error NotCollateralized();
    error NotForSale();
    error NotLiquidatable();
    error Paused();
    error ReentrantCallBlocked();
    error SupplyCapExceeded();
    error TimestampTooLarge();
    error TooManyAssets();
    error TooMuchSlippage();
    error TransferInFailed();
    error TransferOutFailed();
    error Unauthorized();

    event Supply(address indexed from, address indexed dst, uint amount);
    event Transfer(address indexed from, address indexed to, uint amount);
    event Withdraw(address indexed src, address indexed to, uint amount);

    event SupplyCollateral(address indexed from, address indexed dst, address indexed asset, uint amount);
    event TransferCollateral(address indexed from, address indexed to, address indexed asset, uint amount);
    event WithdrawCollateral(address indexed src, address indexed to, address indexed asset, uint amount);

    /// @notice Event emitted when a borrow position is absorbed by the protocol
    event AbsorbDebt(address indexed absorber, address indexed borrower, uint basePaidOut, uint usdValue);

    /// @notice Event emitted when a user's collateral is absorbed by the protocol
    event AbsorbCollateral(address indexed absorber, address indexed borrower, address indexed asset, uint collateralAbsorbed, uint usdValue);

    /// @notice Event emitted when a collateral asset is purchased from the protocol
    event BuyCollateral(address indexed buyer, address indexed asset, uint baseAmount, uint collateralAmount);

    /// @notice Event emitted when an action is paused/unpaused
    event PauseAction(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused);

    /// @notice Event emitted when reserves are withdrawn by the governor
    event WithdrawReserves(address indexed to, uint amount);

    function supply(address asset, uint amount) virtual external;
    function supplyTo(address dst, address asset, uint amount) virtual external;
    function supplyFrom(address from, address dst, address asset, uint amount) virtual external;

    function transfer(address dst, uint amount) virtual external returns (bool);
    function transferFrom(address src, address dst, uint amount) virtual external returns (bool);

    function transferAsset(address dst, address asset, uint amount) virtual external;
    function transferAssetFrom(address src, address dst, address asset, uint amount) virtual external;

    function withdraw(address asset, uint amount) virtual external;
    function withdrawTo(address to, address asset, uint amount) virtual external;
    function withdrawFrom(address src, address to, address asset, uint amount) virtual external;

    function approveThis(address manager, address asset, uint amount) virtual external;
    function withdrawReserves(address to, uint amount) virtual external;

    function absorb(address absorber, address[] calldata accounts) virtual external;
    function buyCollateral(address asset, uint minAmount, uint baseAmount, address recipient) virtual external;
    function quoteCollateral(address asset, uint baseAmount) virtual public view returns (uint);

    function getAssetInfo(uint8 i) virtual public view returns (AssetInfo memory);
    function getAssetInfoByAddress(address asset) virtual public view returns (AssetInfo memory);
    function getCollateralReserves(address asset) virtual public view returns (uint);
    function getReserves() virtual public view returns (int);
    function getPrice(address priceFeed) virtual public view returns (uint);

    function isBorrowCollateralized(address account) virtual public view returns (bool);
    function isLiquidatable(address account) virtual public view returns (bool);

    function totalSupply() virtual external view returns (uint256);
    function totalBorrow() virtual external view returns (uint256);
    function balanceOf(address owner) virtual public view returns (uint256);
    function borrowBalanceOf(address account) virtual public view returns (uint256);

    function pause(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused) virtual external;
    function isSupplyPaused() virtual public view returns (bool);
    function isTransferPaused() virtual public view returns (bool);
    function isWithdrawPaused() virtual public view returns (bool);
    function isAbsorbPaused() virtual public view returns (bool);
    function isBuyPaused() virtual public view returns (bool);

    function accrueAccount(address account) virtual external;
    function getSupplyRate(uint utilization) virtual public view returns (uint64);
    function getBorrowRate(uint utilization) virtual public view returns (uint64);
    function getUtilization() virtual public view returns (uint);

    function governor() virtual external view returns (address);
    function pauseGuardian() virtual external view returns (address);
    function baseToken() virtual external view returns (address);
    function baseTokenPriceFeed() virtual external view returns (address);
    function extensionDelegate() virtual external view returns (address);

    /// @dev uint64
    function supplyKink() virtual external view returns (uint);
    /// @dev uint64
    function supplyPerSecondInterestRateSlopeLow() virtual external view returns (uint);
    /// @dev uint64
    function supplyPerSecondInterestRateSlopeHigh() virtual external view returns (uint);
    /// @dev uint64
    function supplyPerSecondInterestRateBase() virtual external view returns (uint);
    /// @dev uint64
    function borrowKink() virtual external view returns (uint);
    /// @dev uint64
    function borrowPerSecondInterestRateSlopeLow() virtual external view returns (uint);
    /// @dev uint64
    function borrowPerSecondInterestRateSlopeHigh() virtual external view returns (uint);
    /// @dev uint64
    function borrowPerSecondInterestRateBase() virtual external view returns (uint);
    /// @dev uint64
    function storeFrontPriceFactor() virtual external view returns (uint);

    /// @dev uint64
    function baseScale() virtual external view returns (uint);
    /// @dev uint64
    function trackingIndexScale() virtual external view returns (uint);

    /// @dev uint64
    function baseTrackingSupplySpeed() virtual external view returns (uint);
    /// @dev uint64
    function baseTrackingBorrowSpeed() virtual external view returns (uint);
    /// @dev uint104
    function baseMinForRewards() virtual external view returns (uint);
    /// @dev uint104
    function baseBorrowMin() virtual external view returns (uint);
    /// @dev uint104
    function targetReserves() virtual external view returns (uint);

    function numAssets() virtual external view returns (uint8);
    function decimals() virtual external view returns (uint8);

    function initializeStorage() virtual external;
}

File 5 of 12 : CometMath.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title Compound's Comet Math Contract
 * @dev Pure math functions
 * @author Compound
 */
contract CometMath {
    /** Custom errors **/

    error InvalidUInt64();
    error InvalidUInt104();
    error InvalidUInt128();
    error InvalidInt104();
    error InvalidInt256();
    error NegativeNumber();

    function safe64(uint n) internal pure returns (uint64) {
        if (n > type(uint64).max) revert InvalidUInt64();
        return uint64(n);
    }

    function safe104(uint n) internal pure returns (uint104) {
        if (n > type(uint104).max) revert InvalidUInt104();
        return uint104(n);
    }

    function safe128(uint n) internal pure returns (uint128) {
        if (n > type(uint128).max) revert InvalidUInt128();
        return uint128(n);
    }

    function signed104(uint104 n) internal pure returns (int104) {
        if (n > uint104(type(int104).max)) revert InvalidInt104();
        return int104(n);
    }

    function signed256(uint256 n) internal pure returns (int256) {
        if (n > uint256(type(int256).max)) revert InvalidInt256();
        return int256(n);
    }

    function unsigned104(int104 n) internal pure returns (uint104) {
        if (n < 0) revert NegativeNumber();
        return uint104(n);
    }

    function unsigned256(int256 n) internal pure returns (uint256) {
        if (n < 0) revert NegativeNumber();
        return uint256(n);
    }

    function toUInt8(bool x) internal pure returns (uint8) {
        return x ? 1 : 0;
    }

    function toBool(uint8 x) internal pure returns (bool) {
        return x != 0;
    }
}

File 6 of 12 : CometStorage.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title Compound's Comet Storage Interface
 * @dev Versions can enforce append-only storage slots via inheritance.
 * @author Compound
 */
contract CometStorage {
    // 512 bits total = 2 slots
    struct TotalsBasic {
        // 1st slot
        uint64 baseSupplyIndex;
        uint64 baseBorrowIndex;
        uint64 trackingSupplyIndex;
        uint64 trackingBorrowIndex;
        // 2nd slot
        uint104 totalSupplyBase;
        uint104 totalBorrowBase;
        uint40 lastAccrualTime;
        uint8 pauseFlags;
    }

    struct TotalsCollateral {
        uint128 totalSupplyAsset;
        uint128 _reserved;
    }

    struct UserBasic {
        int104 principal;
        uint64 baseTrackingIndex;
        uint64 baseTrackingAccrued;
        uint16 assetsIn;
        uint8 _reserved;
    }

    struct UserCollateral {
        uint128 balance;
        uint128 _reserved;
    }

    struct LiquidatorPoints {
        uint32 numAbsorbs;
        uint64 numAbsorbed;
        uint128 approxSpend;
        uint32 _reserved;
    }

    /// @dev Aggregate variables tracked for the entire market
    uint64 internal baseSupplyIndex;
    uint64 internal baseBorrowIndex;
    uint64 internal trackingSupplyIndex;
    uint64 internal trackingBorrowIndex;
    uint104 internal totalSupplyBase;
    uint104 internal totalBorrowBase;
    uint40 internal lastAccrualTime;
    uint8 internal pauseFlags;

    /// @notice Aggregate variables tracked for each collateral asset
    mapping(address => TotalsCollateral) public totalsCollateral;

    /// @notice Mapping of users to accounts which may be permitted to manage the user account
    mapping(address => mapping(address => bool)) public isAllowed;

    /// @notice The next expected nonce for an address, for validating authorizations via signature
    mapping(address => uint) public userNonce;

    /// @notice Mapping of users to base principal and other basic data
    mapping(address => UserBasic) public userBasic;

    /// @notice Mapping of users to collateral data per collateral asset
    mapping(address => mapping(address => UserCollateral)) public userCollateral;

    /// @notice Mapping of magic liquidator points
    mapping(address => LiquidatorPoints) public liquidatorPoints;
}

File 7 of 12 : CometWithExtendedAssetList.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometMainInterface.sol";
import "./IERC20NonStandard.sol";
import "./IPriceFeed.sol";
import "./IAssetListFactory.sol";
import "./IAssetListFactoryHolder.sol";
import "./IAssetList.sol";

/**
 * @title Compound's Comet Contract
 * @notice An efficient monolithic money market protocol
 * @author Compound
 */
contract CometWithExtendedAssetList is CometMainInterface {
    /** General configuration constants **/

    /// @notice The admin of the protocol
    address public override immutable governor;

    /// @notice The account which may trigger pauses
    address public override immutable pauseGuardian;

    /// @notice The address of the base token contract
    address public override immutable baseToken;

    /// @notice The address of the price feed for the base token
    address public override immutable baseTokenPriceFeed;

    /// @notice The address of the extension contract delegate
    address public override immutable extensionDelegate;

    /// @notice The point in the supply rates separating the low interest rate slope and the high interest rate slope (factor)
    /// @dev uint64
    uint public override immutable supplyKink;

    /// @notice Per second supply interest rate slope applied when utilization is below kink (factor)
    /// @dev uint64
    uint public override immutable supplyPerSecondInterestRateSlopeLow;

    /// @notice Per second supply interest rate slope applied when utilization is above kink (factor)
    /// @dev uint64
    uint public override immutable supplyPerSecondInterestRateSlopeHigh;

    /// @notice Per second supply base interest rate (factor)
    /// @dev uint64
    uint public override immutable supplyPerSecondInterestRateBase;

    /// @notice The point in the borrow rate separating the low interest rate slope and the high interest rate slope (factor)
    /// @dev uint64
    uint public override immutable borrowKink;

    /// @notice Per second borrow interest rate slope applied when utilization is below kink (factor)
    /// @dev uint64
    uint public override immutable borrowPerSecondInterestRateSlopeLow;

    /// @notice Per second borrow interest rate slope applied when utilization is above kink (factor)
    /// @dev uint64
    uint public override immutable borrowPerSecondInterestRateSlopeHigh;

    /// @notice Per second borrow base interest rate (factor)
    /// @dev uint64
    uint public override immutable borrowPerSecondInterestRateBase;

    /// @notice The fraction of the liquidation penalty that goes to buyers of collateral instead of the protocol
    /// @dev uint64
    uint public override immutable storeFrontPriceFactor;

    /// @notice The scale for base token (must be less than 18 decimals)
    /// @dev uint64
    uint public override immutable baseScale;

    /// @notice The scale for reward tracking
    /// @dev uint64
    uint public override immutable trackingIndexScale;

    /// @notice The speed at which supply rewards are tracked (in trackingIndexScale)
    /// @dev uint64
    uint public override immutable baseTrackingSupplySpeed;

    /// @notice The speed at which borrow rewards are tracked (in trackingIndexScale)
    /// @dev uint64
    uint public override immutable baseTrackingBorrowSpeed;

    /// @notice The minimum amount of base principal wei for rewards to accrue
    /// @dev This must be large enough so as to prevent division by base wei from overflowing the 64 bit indices
    /// @dev uint104
    uint public override immutable baseMinForRewards;

    /// @notice The minimum base amount required to initiate a borrow
    uint public override immutable baseBorrowMin;

    /// @notice The minimum base token reserves which must be held before collateral is hodled
    uint public override immutable targetReserves;

    /// @notice The number of decimals for wrapped base token
    uint8 public override immutable decimals;

    /// @notice The number of assets this contract actually supports
    uint8 public override immutable numAssets;

    /// @notice Factor to divide by when accruing rewards in order to preserve 6 decimals (i.e. baseScale / 1e6)
    uint internal immutable accrualDescaleFactor;
    
    /// @notice The address of the asset list
    address immutable public assetList;

    uint8 internal constant MAX_ASSETS_FOR_ASSET_LIST = 24;

    /**
     * @notice Construct a new protocol instance
     * @param config The mapping of initial/constant parameters
     **/
    constructor(Configuration memory config) {
        // Sanity checks
        uint8 decimals_ = IERC20NonStandard(config.baseToken).decimals();
        if (decimals_ > MAX_BASE_DECIMALS) revert BadDecimals();
        if (config.storeFrontPriceFactor > FACTOR_SCALE) revert BadDiscount();
        if (config.assetConfigs.length > MAX_ASSETS_FOR_ASSET_LIST) revert TooManyAssets();
        if (config.baseMinForRewards == 0) revert BadMinimum();
        if (IPriceFeed(config.baseTokenPriceFeed).decimals() != PRICE_FEED_DECIMALS) revert BadDecimals();

        // Copy configuration
        unchecked {
            governor = config.governor;
            pauseGuardian = config.pauseGuardian;
            baseToken = config.baseToken;
            baseTokenPriceFeed = config.baseTokenPriceFeed;
            extensionDelegate = config.extensionDelegate;
            storeFrontPriceFactor = config.storeFrontPriceFactor;

            decimals = decimals_;
            baseScale = uint64(10 ** decimals_);
            trackingIndexScale = config.trackingIndexScale;
            if (baseScale < BASE_ACCRUAL_SCALE) revert BadDecimals();
            accrualDescaleFactor = baseScale / BASE_ACCRUAL_SCALE;

            baseMinForRewards = config.baseMinForRewards;
            baseTrackingSupplySpeed = config.baseTrackingSupplySpeed;
            baseTrackingBorrowSpeed = config.baseTrackingBorrowSpeed;

            baseBorrowMin = config.baseBorrowMin;
            targetReserves = config.targetReserves;
        }

        // Set interest rate model configs
        unchecked {
            supplyKink = config.supplyKink;
            supplyPerSecondInterestRateSlopeLow = config.supplyPerYearInterestRateSlopeLow / SECONDS_PER_YEAR;
            supplyPerSecondInterestRateSlopeHigh = config.supplyPerYearInterestRateSlopeHigh / SECONDS_PER_YEAR;
            supplyPerSecondInterestRateBase = config.supplyPerYearInterestRateBase / SECONDS_PER_YEAR;
            borrowKink = config.borrowKink;
            borrowPerSecondInterestRateSlopeLow = config.borrowPerYearInterestRateSlopeLow / SECONDS_PER_YEAR;
            borrowPerSecondInterestRateSlopeHigh = config.borrowPerYearInterestRateSlopeHigh / SECONDS_PER_YEAR;
            borrowPerSecondInterestRateBase = config.borrowPerYearInterestRateBase / SECONDS_PER_YEAR;
        }

        // Set asset info
        numAssets = uint8(config.assetConfigs.length);

        assetList = IAssetListFactory(IAssetListFactoryHolder(extensionDelegate).assetListFactory()).createAssetList(config.assetConfigs);
    }

    /**
     * @dev Prevents marked functions from being reentered 
     * Note: this restrict contracts from calling comet functions in their hooks.
     * Doing so will cause the transaction to revert.
     */
    modifier nonReentrant() {
        nonReentrantBefore();
        _;
        nonReentrantAfter();
    }

    /**
     * @dev Checks that the reentrancy flag is not set and then sets the flag
     */
    function nonReentrantBefore() internal {
        bytes32 slot = REENTRANCY_GUARD_FLAG_SLOT;
        uint256 status;
        assembly ("memory-safe") {
            status := sload(slot)
        }

        if (status == REENTRANCY_GUARD_ENTERED) revert ReentrantCallBlocked();
        assembly ("memory-safe") {
            sstore(slot, REENTRANCY_GUARD_ENTERED)
        }
    }

    /**
     * @dev Unsets the reentrancy flag
     */
    function nonReentrantAfter() internal {
        bytes32 slot = REENTRANCY_GUARD_FLAG_SLOT;
        uint256 status;
        assembly ("memory-safe") {
            sstore(slot, REENTRANCY_GUARD_NOT_ENTERED)
        }
    }

    /**
     * @notice Initialize storage for the contract
     * @dev Can be used from constructor or proxy
     */
    function initializeStorage() override external {
        if (lastAccrualTime != 0) revert AlreadyInitialized();

        // Initialize aggregates
        lastAccrualTime = getNowInternal();
        baseSupplyIndex = BASE_INDEX_SCALE;
        baseBorrowIndex = BASE_INDEX_SCALE;

        // Implicit initialization (not worth increasing contract size)
        // trackingSupplyIndex = 0;
        // trackingBorrowIndex = 0;
    }

    /**
     * @notice Get the i-th asset info, according to the order they were passed in originally
     * @param i The index of the asset info to get
     * @return The asset info object
     */
    function getAssetInfo(uint8 i) override public view returns (AssetInfo memory) {
        return IAssetList(assetList).getAssetInfo(i);
    }

    /**
     * @dev Determine index of asset that matches given address
     */
    function getAssetInfoByAddress(address asset) override public view returns (AssetInfo memory) {
        for (uint8 i = 0; i < numAssets; ) {
            AssetInfo memory assetInfo = getAssetInfo(i);
            if (assetInfo.asset == asset) {
                return assetInfo;
            }
            unchecked { i++; }
        }
        revert BadAsset();
    }

    /**
     * @return The current timestamp
     **/
    function getNowInternal() virtual internal view returns (uint40) {
        if (block.timestamp >= 2**40) revert TimestampTooLarge();
        return uint40(block.timestamp);
    }

    /**
     * @dev Calculate accrued interest indices for base token supply and borrows
     **/
    function accruedInterestIndices(uint timeElapsed) internal view returns (uint64, uint64) {
        uint64 baseSupplyIndex_ = baseSupplyIndex;
        uint64 baseBorrowIndex_ = baseBorrowIndex;
        if (timeElapsed > 0) {
            uint utilization = getUtilization();
            uint supplyRate = getSupplyRate(utilization);
            uint borrowRate = getBorrowRate(utilization);
            baseSupplyIndex_ += safe64(mulFactor(baseSupplyIndex_, supplyRate * timeElapsed));
            baseBorrowIndex_ += safe64(mulFactor(baseBorrowIndex_, borrowRate * timeElapsed));
        }
        return (baseSupplyIndex_, baseBorrowIndex_);
    }

    /**
     * @dev Accrue interest (and rewards) in base token supply and borrows
     **/
    function accrueInternal() internal {
        uint40 now_ = getNowInternal();
        uint timeElapsed = uint256(now_ - lastAccrualTime);
        if (timeElapsed > 0) {
            (baseSupplyIndex, baseBorrowIndex) = accruedInterestIndices(timeElapsed);
            if (totalSupplyBase >= baseMinForRewards) {
                trackingSupplyIndex += safe64(divBaseWei(baseTrackingSupplySpeed * timeElapsed, totalSupplyBase));
            }
            if (totalBorrowBase >= baseMinForRewards) {
                trackingBorrowIndex += safe64(divBaseWei(baseTrackingBorrowSpeed * timeElapsed, totalBorrowBase));
            }
            lastAccrualTime = now_;
        }
    }

    /**
     * @notice Accrue interest and rewards for an account
     **/
    function accrueAccount(address account) override external {
        accrueInternal();

        UserBasic memory basic = userBasic[account];
        updateBasePrincipal(account, basic, basic.principal);
    }

    /**
     * @dev Note: Does not accrue interest first
     * @param utilization The utilization to check the supply rate for
     * @return The per second supply rate at `utilization`
     */
    function getSupplyRate(uint utilization) override public view returns (uint64) {
        if (utilization <= supplyKink) {
            // interestRateBase + interestRateSlopeLow * utilization
            return safe64(supplyPerSecondInterestRateBase + mulFactor(supplyPerSecondInterestRateSlopeLow, utilization));
        } else {
            // interestRateBase + interestRateSlopeLow * kink + interestRateSlopeHigh * (utilization - kink)
            return safe64(supplyPerSecondInterestRateBase + mulFactor(supplyPerSecondInterestRateSlopeLow, supplyKink) + mulFactor(supplyPerSecondInterestRateSlopeHigh, (utilization - supplyKink)));
        }
    }

    /**
     * @dev Note: Does not accrue interest first
     * @param utilization The utilization to check the borrow rate for
     * @return The per second borrow rate at `utilization`
     */
    function getBorrowRate(uint utilization) override public view returns (uint64) {
        if (utilization <= borrowKink) {
            // interestRateBase + interestRateSlopeLow * utilization
            return safe64(borrowPerSecondInterestRateBase + mulFactor(borrowPerSecondInterestRateSlopeLow, utilization));
        } else {
            // interestRateBase + interestRateSlopeLow * kink + interestRateSlopeHigh * (utilization - kink)
            return safe64(borrowPerSecondInterestRateBase + mulFactor(borrowPerSecondInterestRateSlopeLow, borrowKink) + mulFactor(borrowPerSecondInterestRateSlopeHigh, (utilization - borrowKink)));
        }
    }

    /**
     * @dev Note: Does not accrue interest first
     * @return The utilization rate of the base asset
     */
    function getUtilization() override public view returns (uint) {
        uint totalSupply_ = presentValueSupply(baseSupplyIndex, totalSupplyBase);
        uint totalBorrow_ = presentValueBorrow(baseBorrowIndex, totalBorrowBase);
        if (totalSupply_ == 0) {
            return 0;
        } else {
            return totalBorrow_ * FACTOR_SCALE / totalSupply_;
        }
    }

    /**
     * @notice Get the current price from a feed
     * @param priceFeed The address of a price feed
     * @return The price, scaled by `PRICE_SCALE`
     */
    function getPrice(address priceFeed) override public view returns (uint256) {
        (, int price, , , ) = IPriceFeed(priceFeed).latestRoundData();
        if (price <= 0) revert BadPrice();
        return uint256(price);
    }

    /**
     * @notice Gets the total balance of protocol collateral reserves for an asset
     * @dev Note: Reverts if collateral reserves are somehow negative, which should not be possible
     * @param asset The collateral asset
     */
    function getCollateralReserves(address asset) override public view returns (uint) {
        return IERC20NonStandard(asset).balanceOf(address(this)) - totalsCollateral[asset].totalSupplyAsset;
    }

    /**
     * @notice Gets the total amount of protocol reserves of the base asset
     */
    function getReserves() override public view returns (int) {
        (uint64 baseSupplyIndex_, uint64 baseBorrowIndex_) = accruedInterestIndices(getNowInternal() - lastAccrualTime);
        uint balance = IERC20NonStandard(baseToken).balanceOf(address(this));
        uint totalSupply_ = presentValueSupply(baseSupplyIndex_, totalSupplyBase);
        uint totalBorrow_ = presentValueBorrow(baseBorrowIndex_, totalBorrowBase);
        return signed256(balance) - signed256(totalSupply_) + signed256(totalBorrow_);
    }

    /**
     * @notice Check whether an account has enough collateral to borrow
     * @param account The address to check
     * @return Whether the account is minimally collateralized enough to borrow
     */
    function isBorrowCollateralized(address account) override public view returns (bool) {
        int104 principal = userBasic[account].principal;

        if (principal >= 0) {
            return true;
        }

        uint16 assetsIn = userBasic[account].assetsIn;
        uint8 _reserved = userBasic[account]._reserved;
        int liquidity = signedMulPrice(
            presentValue(principal),
            getPrice(baseTokenPriceFeed),
            uint64(baseScale)
        );

        for (uint8 i = 0; i < numAssets; ) {
            if (isInAsset(assetsIn, i, _reserved)) {
                if (liquidity >= 0) {
                    return true;
                }

                AssetInfo memory asset = getAssetInfo(i);
                uint newAmount = mulPrice(
                    userCollateral[account][asset.asset].balance,
                    getPrice(asset.priceFeed),
                    asset.scale
                );
                liquidity += signed256(mulFactor(
                    newAmount,
                    asset.borrowCollateralFactor
                ));
            }
            unchecked { i++; }
        }

        return liquidity >= 0;
    }

    /**
     * @notice Check whether an account has enough collateral to not be liquidated
     * @param account The address to check
     * @return Whether the account is minimally collateralized enough to not be liquidated
     */
    function isLiquidatable(address account) override public view returns (bool) {
        int104 principal = userBasic[account].principal;

        if (principal >= 0) {
            return false;
        }

        uint16 assetsIn = userBasic[account].assetsIn;
        uint8 _reserved = userBasic[account]._reserved;
        int liquidity = signedMulPrice(
            presentValue(principal),
            getPrice(baseTokenPriceFeed),
            uint64(baseScale)
        );

        for (uint8 i = 0; i < numAssets; ) {
            if (isInAsset(assetsIn, i, _reserved)) {
                if (liquidity >= 0) {
                    return false;
                }

                AssetInfo memory asset = getAssetInfo(i);
                uint newAmount = mulPrice(
                    userCollateral[account][asset.asset].balance,
                    getPrice(asset.priceFeed),
                    asset.scale
                );
                liquidity += signed256(mulFactor(
                    newAmount,
                    asset.liquidateCollateralFactor
                ));
            }
            unchecked { i++; }
        }

        return liquidity < 0;
    }

    /**
     * @dev The change in principal broken into repay and supply amounts
     */
    function repayAndSupplyAmount(int104 oldPrincipal, int104 newPrincipal) internal pure returns (uint104, uint104) {
        // If the new principal is less than the old principal, then no amount has been repaid or supplied
        if (newPrincipal < oldPrincipal) return (0, 0);

        if (newPrincipal <= 0) {
            return (uint104(newPrincipal - oldPrincipal), 0);
        } else if (oldPrincipal >= 0) {
            return (0, uint104(newPrincipal - oldPrincipal));
        } else {
            return (uint104(-oldPrincipal), uint104(newPrincipal));
        }
    }

    /**
     * @dev The change in principal broken into withdraw and borrow amounts
     */
    function withdrawAndBorrowAmount(int104 oldPrincipal, int104 newPrincipal) internal pure returns (uint104, uint104) {
        // If the new principal is greater than the old principal, then no amount has been withdrawn or borrowed
        if (newPrincipal > oldPrincipal) return (0, 0);

        if (newPrincipal >= 0) {
            return (uint104(oldPrincipal - newPrincipal), 0);
        } else if (oldPrincipal <= 0) {
            return (0, uint104(oldPrincipal - newPrincipal));
        } else {
            return (uint104(oldPrincipal), uint104(-newPrincipal));
        }
    }

    /**
     * @notice Pauses different actions within Comet
     * @param supplyPaused Boolean for pausing supply actions
     * @param transferPaused Boolean for pausing transfer actions
     * @param withdrawPaused Boolean for pausing withdraw actions
     * @param absorbPaused Boolean for pausing absorb actions
     * @param buyPaused Boolean for pausing buy actions
     */
    function pause(
        bool supplyPaused,
        bool transferPaused,
        bool withdrawPaused,
        bool absorbPaused,
        bool buyPaused
    ) override external {
        if (msg.sender != governor && msg.sender != pauseGuardian) revert Unauthorized();

        pauseFlags =
            uint8(0) |
            (toUInt8(supplyPaused) << PAUSE_SUPPLY_OFFSET) |
            (toUInt8(transferPaused) << PAUSE_TRANSFER_OFFSET) |
            (toUInt8(withdrawPaused) << PAUSE_WITHDRAW_OFFSET) |
            (toUInt8(absorbPaused) << PAUSE_ABSORB_OFFSET) |
            (toUInt8(buyPaused) << PAUSE_BUY_OFFSET);

        emit PauseAction(supplyPaused, transferPaused, withdrawPaused, absorbPaused, buyPaused);
    }

    /**
     * @return Whether or not supply actions are paused
     */
    function isSupplyPaused() override public view returns (bool) {
        return toBool(pauseFlags & (uint8(1) << PAUSE_SUPPLY_OFFSET));
    }

    /**
     * @return Whether or not transfer actions are paused
     */
    function isTransferPaused() override public view returns (bool) {
        return toBool(pauseFlags & (uint8(1) << PAUSE_TRANSFER_OFFSET));
    }

    /**
     * @return Whether or not withdraw actions are paused
     */
    function isWithdrawPaused() override public view returns (bool) {
        return toBool(pauseFlags & (uint8(1) << PAUSE_WITHDRAW_OFFSET));
    }

    /**
     * @return Whether or not absorb actions are paused
     */
    function isAbsorbPaused() override public view returns (bool) {
        return toBool(pauseFlags & (uint8(1) << PAUSE_ABSORB_OFFSET));
    }

    /**
     * @return Whether or not buy actions are paused
     */
    function isBuyPaused() override public view returns (bool) {
        return toBool(pauseFlags & (uint8(1) << PAUSE_BUY_OFFSET));
    }

    /**
     * @dev Multiply a number by a factor
     */
    function mulFactor(uint n, uint factor) internal pure returns (uint) {
        return n * factor / FACTOR_SCALE;
    }

    /**
     * @dev Divide a number by an amount of base
     */
    function divBaseWei(uint n, uint baseWei) internal view returns (uint) {
        return n * baseScale / baseWei;
    }

    /**
     * @dev Multiply a `fromScale` quantity by a price, returning a common price quantity
     */
    function mulPrice(uint n, uint price, uint64 fromScale) internal pure returns (uint) {
        return n * price / fromScale;
    }

    /**
     * @dev Multiply a signed `fromScale` quantity by a price, returning a common price quantity
     */
    function signedMulPrice(int n, uint price, uint64 fromScale) internal pure returns (int) {
        return n * signed256(price) / int256(uint256(fromScale));
    }

    /**
     * @dev Divide a common price quantity by a price, returning a `toScale` quantity
     */
    function divPrice(uint n, uint price, uint64 toScale) internal pure returns (uint) {
        return n * toScale / price;
    }

    /**
     * @dev Whether user has a non-zero balance of an asset, given assetsIn flags
     * @dev _reserved is used to check bits 16-23 of assetsIn
     */
    function isInAsset(uint16 assetsIn, uint8 assetOffset, uint8 _reserved) internal pure returns (bool) {
        if (assetOffset < 16) {
            // check bit in assetsIn (for bits 0-15)
            return (assetsIn & (uint16(1) << assetOffset)) != 0;
        } else if (assetOffset < 24) {
            // check bit in reserved (for bits 16-23)
            return (_reserved & (uint8(1) << (assetOffset - 16))) != 0;
        }
        return false; // if assetOffset >= 24 (should not happen)
    }

    /**
     * @dev Update assetsIn bit vector if user has entered or exited an asset
     */
    function updateAssetsIn(
        address account,
        AssetInfo memory assetInfo,
        uint128 initialUserBalance,
        uint128 finalUserBalance
    ) internal {
        if (initialUserBalance == 0 && finalUserBalance != 0) {
            // set bit for asset
            if (assetInfo.offset < 16) {
                // set bit in assetsIn for bits 0-15
                userBasic[account].assetsIn |= (uint16(1) << assetInfo.offset);
            } else if (assetInfo.offset < 24) {
                // set bit in _reserved for bits 16-23
                userBasic[account]._reserved |= (uint8(1) << (assetInfo.offset - 16));
            }
        } else if (initialUserBalance != 0 && finalUserBalance == 0) {
            // clear bit for asset
            if (assetInfo.offset < 16) {
                // clear bit in assetsIn for bits 0-15
                userBasic[account].assetsIn &= ~(uint16(1) << assetInfo.offset);
            } else if (assetInfo.offset < 24) {
                // clear bit in _reserved for bits 16-23
                userBasic[account]._reserved &= ~(uint8(1) << (assetInfo.offset - 16));
            }
        }
    }

    /**
     * @dev Write updated principal to store and tracking participation
     */
    function updateBasePrincipal(address account, UserBasic memory basic, int104 principalNew) internal {
        int104 principal = basic.principal;
        basic.principal = principalNew;

        if (principal >= 0) {
            uint indexDelta = uint256(trackingSupplyIndex - basic.baseTrackingIndex);
            basic.baseTrackingAccrued += safe64(uint104(principal) * indexDelta / trackingIndexScale / accrualDescaleFactor);
        } else {
            uint indexDelta = uint256(trackingBorrowIndex - basic.baseTrackingIndex);
            basic.baseTrackingAccrued += safe64(uint104(-principal) * indexDelta / trackingIndexScale / accrualDescaleFactor);
        }

        if (principalNew >= 0) {
            basic.baseTrackingIndex = trackingSupplyIndex;
        } else {
            basic.baseTrackingIndex = trackingBorrowIndex;
        }

        userBasic[account] = basic;
    }

    /**
     * @dev Safe ERC20 transfer in and returns the final amount transferred (taking into account any fees)
     * @dev Note: Safely handles non-standard ERC-20 tokens that do not return a value. See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
     */
    function doTransferIn(address asset, address from, uint amount) internal returns (uint) {
        uint256 preTransferBalance = IERC20NonStandard(asset).balanceOf(address(this));
        IERC20NonStandard(asset).transferFrom(from, address(this), amount);
        bool success;
        assembly ("memory-safe") {
            switch returndatasize()
                case 0 {                       // This is a non-standard ERC-20
                    success := not(0)          // set success to true
                }
                case 32 {                      // This is a compliant ERC-20
                    returndatacopy(0, 0, 32)
                    success := mload(0)        // Set `success = returndata` of override external call
                }
                default {                      // This is an excessively non-compliant ERC-20, revert.
                    revert(0, 0)
                }
        }
        if (!success) revert TransferInFailed();
        return IERC20NonStandard(asset).balanceOf(address(this)) - preTransferBalance;
    }

    /**
     * @dev Safe ERC20 transfer out
     * @dev Note: Safely handles non-standard ERC-20 tokens that do not return a value. See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
     */
    function doTransferOut(address asset, address to, uint amount) internal {
        IERC20NonStandard(asset).transfer(to, amount);
        bool success;
        assembly ("memory-safe") {
            switch returndatasize()
                case 0 {                       // This is a non-standard ERC-20
                    success := not(0)          // set success to true
                }
                case 32 {                      // This is a compliant ERC-20
                    returndatacopy(0, 0, 32)
                    success := mload(0)        // Set `success = returndata` of override external call
                }
                default {                      // This is an excessively non-compliant ERC-20, revert.
                    revert(0, 0)
                }
        }
        if (!success) revert TransferOutFailed();
    }

    /**
     * @notice Supply an amount of asset to the protocol
     * @param asset The asset to supply
     * @param amount The quantity to supply
     */
    function supply(address asset, uint amount) override external {
        return supplyInternal(msg.sender, msg.sender, msg.sender, asset, amount);
    }

    /**
     * @notice Supply an amount of asset to dst
     * @param dst The address which will hold the balance
     * @param asset The asset to supply
     * @param amount The quantity to supply
     */
    function supplyTo(address dst, address asset, uint amount) override external {
        return supplyInternal(msg.sender, msg.sender, dst, asset, amount);
    }

    /**
     * @notice Supply an amount of asset from `from` to dst, if allowed
     * @param from The supplier address
     * @param dst The address which will hold the balance
     * @param asset The asset to supply
     * @param amount The quantity to supply
     */
    function supplyFrom(address from, address dst, address asset, uint amount) override external {
        return supplyInternal(msg.sender, from, dst, asset, amount);
    }

    /**
     * @dev Supply either collateral or base asset, depending on the asset, if operator is allowed
     * @dev Note: Specifying an `amount` of uint256.max will repay all of `dst`'s accrued base borrow balance
     */
    function supplyInternal(address operator, address from, address dst, address asset, uint amount) internal nonReentrant {
        if (isSupplyPaused()) revert Paused();
        if (!hasPermission(from, operator)) revert Unauthorized();

        if (asset == baseToken) {
            if (amount == type(uint256).max) {
                amount = borrowBalanceOf(dst);
            }
            return supplyBase(from, dst, amount);
        } else {
            return supplyCollateral(from, dst, asset, safe128(amount));
        }
    }

    /**
     * @dev Supply an amount of base asset from `from` to dst
     */
    function supplyBase(address from, address dst, uint256 amount) internal {
        amount = doTransferIn(baseToken, from, amount);

        accrueInternal();

        UserBasic memory dstUser = userBasic[dst];
        int104 dstPrincipal = dstUser.principal;
        int256 dstBalance = presentValue(dstPrincipal) + signed256(amount);
        int104 dstPrincipalNew = principalValue(dstBalance);

        (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(dstPrincipal, dstPrincipalNew);

        totalSupplyBase += supplyAmount;
        totalBorrowBase -= repayAmount;

        updateBasePrincipal(dst, dstUser, dstPrincipalNew);

        emit Supply(from, dst, amount);

        if (supplyAmount > 0) {
            emit Transfer(address(0), dst, presentValueSupply(baseSupplyIndex, supplyAmount));
        }
    }

    /**
     * @dev Supply an amount of collateral asset from `from` to dst
     */
    function supplyCollateral(address from, address dst, address asset, uint128 amount) internal {
        amount = safe128(doTransferIn(asset, from, amount));

        AssetInfo memory assetInfo = getAssetInfoByAddress(asset);
        TotalsCollateral memory totals = totalsCollateral[asset];
        totals.totalSupplyAsset += amount;
        if (totals.totalSupplyAsset > assetInfo.supplyCap) revert SupplyCapExceeded();

        uint128 dstCollateral = userCollateral[dst][asset].balance;
        uint128 dstCollateralNew = dstCollateral + amount;

        totalsCollateral[asset] = totals;
        userCollateral[dst][asset].balance = dstCollateralNew;

        updateAssetsIn(dst, assetInfo, dstCollateral, dstCollateralNew);

        emit SupplyCollateral(from, dst, asset, amount);
    }

    /**
     * @notice ERC20 transfer an amount of base token to dst
     * @param dst The recipient address
     * @param amount The quantity to transfer
     * @return true
     */
    function transfer(address dst, uint amount) override external returns (bool) {
        transferInternal(msg.sender, msg.sender, dst, baseToken, amount);
        return true;
    }

    /**
     * @notice ERC20 transfer an amount of base token from src to dst, if allowed
     * @param src The sender address
     * @param dst The recipient address
     * @param amount The quantity to transfer
     * @return true
     */
    function transferFrom(address src, address dst, uint amount) override external returns (bool) {
        transferInternal(msg.sender, src, dst, baseToken, amount);
        return true;
    }

    /**
     * @notice Transfer an amount of asset to dst
     * @param dst The recipient address
     * @param asset The asset to transfer
     * @param amount The quantity to transfer
     */
    function transferAsset(address dst, address asset, uint amount) override external {
        return transferInternal(msg.sender, msg.sender, dst, asset, amount);
    }

    /**
     * @notice Transfer an amount of asset from src to dst, if allowed
     * @param src The sender address
     * @param dst The recipient address
     * @param asset The asset to transfer
     * @param amount The quantity to transfer
     */
    function transferAssetFrom(address src, address dst, address asset, uint amount) override external {
        return transferInternal(msg.sender, src, dst, asset, amount);
    }

    /**
     * @dev Transfer either collateral or base asset, depending on the asset, if operator is allowed
     * @dev Note: Specifying an `amount` of uint256.max will transfer all of `src`'s accrued base balance
     */
    function transferInternal(address operator, address src, address dst, address asset, uint amount) internal nonReentrant {
        if (isTransferPaused()) revert Paused();
        if (!hasPermission(src, operator)) revert Unauthorized();
        if (src == dst) revert NoSelfTransfer();

        if (asset == baseToken) {
            if (amount == type(uint256).max) {
                amount = balanceOf(src);
            }
            return transferBase(src, dst, amount);
        } else {
            return transferCollateral(src, dst, asset, safe128(amount));
        }
    }

    /**
     * @dev Transfer an amount of base asset from src to dst, borrowing if possible/necessary
     */
    function transferBase(address src, address dst, uint256 amount) internal {
        accrueInternal();

        UserBasic memory srcUser = userBasic[src];
        UserBasic memory dstUser = userBasic[dst];

        int104 srcPrincipal = srcUser.principal;
        int104 dstPrincipal = dstUser.principal;
        int256 srcBalance = presentValue(srcPrincipal) - signed256(amount);
        int256 dstBalance = presentValue(dstPrincipal) + signed256(amount);
        int104 srcPrincipalNew = principalValue(srcBalance);
        int104 dstPrincipalNew = principalValue(dstBalance);

        (uint104 withdrawAmount, uint104 borrowAmount) = withdrawAndBorrowAmount(srcPrincipal, srcPrincipalNew);
        (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(dstPrincipal, dstPrincipalNew);

        // Note: Instead of `total += addAmount - subAmount` to avoid underflow errors.
        totalSupplyBase = totalSupplyBase + supplyAmount - withdrawAmount;
        totalBorrowBase = totalBorrowBase + borrowAmount - repayAmount;

        updateBasePrincipal(src, srcUser, srcPrincipalNew);
        updateBasePrincipal(dst, dstUser, dstPrincipalNew);

        if (srcBalance < 0) {
            if (uint256(-srcBalance) < baseBorrowMin) revert BorrowTooSmall();
            if (!isBorrowCollateralized(src)) revert NotCollateralized();
        }

        if (withdrawAmount > 0) {
            emit Transfer(src, address(0), presentValueSupply(baseSupplyIndex, withdrawAmount));
        }

        if (supplyAmount > 0) {
            emit Transfer(address(0), dst, presentValueSupply(baseSupplyIndex, supplyAmount));
        }
    }

    /**
     * @dev Transfer an amount of collateral asset from src to dst
     */
    function transferCollateral(address src, address dst, address asset, uint128 amount) internal {
        uint128 srcCollateral = userCollateral[src][asset].balance;
        uint128 dstCollateral = userCollateral[dst][asset].balance;
        uint128 srcCollateralNew = srcCollateral - amount;
        uint128 dstCollateralNew = dstCollateral + amount;

        userCollateral[src][asset].balance = srcCollateralNew;
        userCollateral[dst][asset].balance = dstCollateralNew;

        AssetInfo memory assetInfo = getAssetInfoByAddress(asset);
        updateAssetsIn(src, assetInfo, srcCollateral, srcCollateralNew);
        updateAssetsIn(dst, assetInfo, dstCollateral, dstCollateralNew);

        // Note: no accrue interest, BorrowCF < LiquidationCF covers small changes
        if (!isBorrowCollateralized(src)) revert NotCollateralized();

        emit TransferCollateral(src, dst, asset, amount);
    }

    /**
     * @notice Withdraw an amount of asset from the protocol
     * @param asset The asset to withdraw
     * @param amount The quantity to withdraw
     */
    function withdraw(address asset, uint amount) override external {
        return withdrawInternal(msg.sender, msg.sender, msg.sender, asset, amount);
    }

    /**
     * @notice Withdraw an amount of asset to `to`
     * @param to The recipient address
     * @param asset The asset to withdraw
     * @param amount The quantity to withdraw
     */
    function withdrawTo(address to, address asset, uint amount) override external {
        return withdrawInternal(msg.sender, msg.sender, to, asset, amount);
    }

    /**
     * @notice Withdraw an amount of asset from src to `to`, if allowed
     * @param src The sender address
     * @param to The recipient address
     * @param asset The asset to withdraw
     * @param amount The quantity to withdraw
     */
    function withdrawFrom(address src, address to, address asset, uint amount) override external {
        return withdrawInternal(msg.sender, src, to, asset, amount);
    }

    /**
     * @dev Withdraw either collateral or base asset, depending on the asset, if operator is allowed
     * @dev Note: Specifying an `amount` of uint256.max will withdraw all of `src`'s accrued base balance
     */
    function withdrawInternal(address operator, address src, address to, address asset, uint amount) internal nonReentrant {
        if (isWithdrawPaused()) revert Paused();
        if (!hasPermission(src, operator)) revert Unauthorized();

        if (asset == baseToken) {
            if (amount == type(uint256).max) {
                amount = balanceOf(src);
            }
            return withdrawBase(src, to, amount);
        } else {
            return withdrawCollateral(src, to, asset, safe128(amount));
        }
    }

    /**
     * @dev Withdraw an amount of base asset from src to `to`, borrowing if possible/necessary
     */
    function withdrawBase(address src, address to, uint256 amount) internal {
        accrueInternal();

        UserBasic memory srcUser = userBasic[src];
        int104 srcPrincipal = srcUser.principal;
        int256 srcBalance = presentValue(srcPrincipal) - signed256(amount);
        int104 srcPrincipalNew = principalValue(srcBalance);

        (uint104 withdrawAmount, uint104 borrowAmount) = withdrawAndBorrowAmount(srcPrincipal, srcPrincipalNew);

        totalSupplyBase -= withdrawAmount;
        totalBorrowBase += borrowAmount;

        updateBasePrincipal(src, srcUser, srcPrincipalNew);

        if (srcBalance < 0) {
            if (uint256(-srcBalance) < baseBorrowMin) revert BorrowTooSmall();
            if (!isBorrowCollateralized(src)) revert NotCollateralized();
        }

        doTransferOut(baseToken, to, amount);

        emit Withdraw(src, to, amount);

        if (withdrawAmount > 0) {
            emit Transfer(src, address(0), presentValueSupply(baseSupplyIndex, withdrawAmount));
        }
    }

    /**
     * @dev Withdraw an amount of collateral asset from src to `to`
     */
    function withdrawCollateral(address src, address to, address asset, uint128 amount) internal {
        uint128 srcCollateral = userCollateral[src][asset].balance;
        uint128 srcCollateralNew = srcCollateral - amount;

        totalsCollateral[asset].totalSupplyAsset -= amount;
        userCollateral[src][asset].balance = srcCollateralNew;

        AssetInfo memory assetInfo = getAssetInfoByAddress(asset);
        updateAssetsIn(src, assetInfo, srcCollateral, srcCollateralNew);

        // Note: no accrue interest, BorrowCF < LiquidationCF covers small changes
        if (!isBorrowCollateralized(src)) revert NotCollateralized();

        doTransferOut(asset, to, amount);

        emit WithdrawCollateral(src, to, asset, amount);
    }

    /**
     * @notice Absorb a list of underwater accounts onto the protocol balance sheet
     * @param absorber The recipient of the incentive paid to the caller of absorb
     * @param accounts The list of underwater accounts to absorb
     */
    function absorb(address absorber, address[] calldata accounts) override external {
        if (isAbsorbPaused()) revert Paused();

        uint startGas = gasleft();
        accrueInternal();
        for (uint i = 0; i < accounts.length; ) {
            absorbInternal(absorber, accounts[i]);
            unchecked { i++; }
        }
        uint gasUsed = startGas - gasleft();

        // Note: liquidator points are an imperfect tool for governance,
        //  to be used while evaluating strategies for incentivizing absorption.
        // Using gas price instead of base fee would more accurately reflect spend,
        //  but is also subject to abuse if refunds were to be given automatically.
        LiquidatorPoints memory points = liquidatorPoints[absorber];
        points.numAbsorbs++;
        points.numAbsorbed += safe64(accounts.length);
        points.approxSpend += safe128(gasUsed * block.basefee);
        liquidatorPoints[absorber] = points;
    }

    /**
     * @dev Transfer user's collateral and debt to the protocol itself.
     */
    function absorbInternal(address absorber, address account) internal {
        if (!isLiquidatable(account)) revert NotLiquidatable();

        UserBasic memory accountUser = userBasic[account];
        int104 oldPrincipal = accountUser.principal;
        int256 oldBalance = presentValue(oldPrincipal);
        uint16 assetsIn = accountUser.assetsIn;
        uint8 _reserved = accountUser._reserved;

        uint256 basePrice = getPrice(baseTokenPriceFeed);
        uint256 deltaValue = 0;

        for (uint8 i = 0; i < numAssets; ) {
            if (isInAsset(assetsIn, i, _reserved)) {
                AssetInfo memory assetInfo = getAssetInfo(i);
                address asset = assetInfo.asset;
                uint128 seizeAmount = userCollateral[account][asset].balance;
                userCollateral[account][asset].balance = 0;
                totalsCollateral[asset].totalSupplyAsset -= seizeAmount;

                uint256 value = mulPrice(seizeAmount, getPrice(assetInfo.priceFeed), assetInfo.scale);
                deltaValue += mulFactor(value, assetInfo.liquidationFactor);

                emit AbsorbCollateral(absorber, account, asset, seizeAmount, value);
            }
            unchecked { i++; }
        }

        uint256 deltaBalance = divPrice(deltaValue, basePrice, uint64(baseScale));
        int256 newBalance = oldBalance + signed256(deltaBalance);
        // New balance will not be negative, all excess debt absorbed by reserves
        if (newBalance < 0) {
            newBalance = 0;
        }

        int104 newPrincipal = principalValue(newBalance);
        updateBasePrincipal(account, accountUser, newPrincipal);

        // reset assetsIn
        userBasic[account].assetsIn = 0;
        userBasic[account]._reserved = 0;

        (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(oldPrincipal, newPrincipal);

        // Reserves are decreased by increasing total supply and decreasing borrows
        //  the amount of debt repaid by reserves is `newBalance - oldBalance`
        totalSupplyBase += supplyAmount;
        totalBorrowBase -= repayAmount;

        uint256 basePaidOut = unsigned256(newBalance - oldBalance);
        uint256 valueOfBasePaidOut = mulPrice(basePaidOut, basePrice, uint64(baseScale));
        emit AbsorbDebt(absorber, account, basePaidOut, valueOfBasePaidOut);

        if (newPrincipal > 0) {
            emit Transfer(address(0), account, presentValueSupply(baseSupplyIndex, unsigned104(newPrincipal)));
        }
    }

    /**
     * @notice Buy collateral from the protocol using base tokens, increasing protocol reserves
       A minimum collateral amount should be specified to indicate the maximum slippage acceptable for the buyer.
     * @param asset The asset to buy
     * @param minAmount The minimum amount of collateral tokens that should be received by the buyer
     * @param baseAmount The amount of base tokens used to buy the collateral
     * @param recipient The recipient address
     */
    function buyCollateral(address asset, uint minAmount, uint baseAmount, address recipient) override external nonReentrant {
        if (isBuyPaused()) revert Paused();

        int reserves = getReserves();
        if (reserves >= 0 && uint(reserves) >= targetReserves) revert NotForSale();

        // Note: Re-entrancy can skip the reserves check above on a second buyCollateral call.
        baseAmount = doTransferIn(baseToken, msg.sender, baseAmount);

        uint collateralAmount = quoteCollateral(asset, baseAmount);
        if (collateralAmount < minAmount) revert TooMuchSlippage();
        if (collateralAmount > getCollateralReserves(asset)) revert InsufficientReserves();

        // Note: Pre-transfer hook can re-enter buyCollateral with a stale collateral ERC20 balance.
        //  Assets should not be listed which allow re-entry from pre-transfer now, as too much collateral could be bought.
        //  This is also a problem if quoteCollateral derives its discount from the collateral ERC20 balance.
        doTransferOut(asset, recipient, safe128(collateralAmount));

        emit BuyCollateral(msg.sender, asset, baseAmount, collateralAmount);
    }

    /**
     * @notice Gets the quote for a collateral asset in exchange for an amount of base asset
     * @param asset The collateral asset to get the quote for
     * @param baseAmount The amount of the base asset to get the quote for
     * @return The quote in terms of the collateral asset
     */
    function quoteCollateral(address asset, uint baseAmount) override public view returns (uint) {
        AssetInfo memory assetInfo = getAssetInfoByAddress(asset);
        uint256 assetPrice = getPrice(assetInfo.priceFeed);
        // Store front discount is derived from the collateral asset's liquidationFactor and storeFrontPriceFactor
        // discount = storeFrontPriceFactor * (1e18 - liquidationFactor)
        uint256 discountFactor = mulFactor(storeFrontPriceFactor, FACTOR_SCALE - assetInfo.liquidationFactor);
        uint256 assetPriceDiscounted = mulFactor(assetPrice, FACTOR_SCALE - discountFactor);
        uint256 basePrice = getPrice(baseTokenPriceFeed);
        // # of collateral assets
        // = (TotalValueOfBaseAmount / DiscountedPriceOfCollateralAsset) * assetScale
        // = ((basePrice * baseAmount / baseScale) / assetPriceDiscounted) * assetScale
        return basePrice * baseAmount * assetInfo.scale / assetPriceDiscounted / baseScale;
    }

    /**
     * @notice Withdraws base token reserves if called by the governor
     * @param to An address of the receiver of withdrawn reserves
     * @param amount The amount of reserves to be withdrawn from the protocol
     */
    function withdrawReserves(address to, uint amount) override external {
        if (msg.sender != governor) revert Unauthorized();

        int reserves = getReserves();
        if (reserves < 0 || amount > unsigned256(reserves)) revert InsufficientReserves();

        doTransferOut(baseToken, to, amount);

        emit WithdrawReserves(to, amount);
    }

    /**
     * @notice Sets Comet's ERC20 allowance of an asset for a manager
     * @dev Only callable by governor
     * @dev Note: Setting the `asset` as Comet's address will allow the manager
     * to withdraw from Comet's Comet balance
     * @dev Note: For USDT, if there is non-zero prior allowance, it must be reset to 0 first before setting a new value in proposal
     * @param asset The asset that the manager will gain approval of
     * @param manager The account which will be allowed or disallowed
     * @param amount The amount of an asset to approve
     */
    function approveThis(address manager, address asset, uint amount) override external {
        if (msg.sender != governor) revert Unauthorized();

        IERC20NonStandard(asset).approve(manager, amount);
    }

    /**
     * @notice Get the total number of tokens in circulation
     * @dev Note: uses updated interest indices to calculate
     * @return The supply of tokens
     **/
    function totalSupply() override external view returns (uint256) {
        (uint64 baseSupplyIndex_, ) = accruedInterestIndices(getNowInternal() - lastAccrualTime);
        return presentValueSupply(baseSupplyIndex_, totalSupplyBase);
    }

    /**
     * @notice Get the total amount of debt
     * @dev Note: uses updated interest indices to calculate
     * @return The amount of debt
     **/
    function totalBorrow() override external view returns (uint256) {
        (, uint64 baseBorrowIndex_) = accruedInterestIndices(getNowInternal() - lastAccrualTime);
        return presentValueBorrow(baseBorrowIndex_, totalBorrowBase);
    }

    /**
     * @notice Query the current positive base balance of an account or zero
     * @dev Note: uses updated interest indices to calculate
     * @param account The account whose balance to query
     * @return The present day base balance magnitude of the account, if positive
     */
    function balanceOf(address account) override public view returns (uint256) {
        (uint64 baseSupplyIndex_, ) = accruedInterestIndices(getNowInternal() - lastAccrualTime);
        int104 principal = userBasic[account].principal;
        return principal > 0 ? presentValueSupply(baseSupplyIndex_, unsigned104(principal)) : 0;
    }

    /**
     * @notice Query the current negative base balance of an account or zero
     * @dev Note: uses updated interest indices to calculate
     * @param account The account whose balance to query
     * @return The present day base balance magnitude of the account, if negative
     */
    function borrowBalanceOf(address account) override public view returns (uint256) {
        (, uint64 baseBorrowIndex_) = accruedInterestIndices(getNowInternal() - lastAccrualTime);
        int104 principal = userBasic[account].principal;
        return principal < 0 ? presentValueBorrow(baseBorrowIndex_, unsigned104(-principal)) : 0;
    }

    /**
     * @notice Fallback to calling the extension delegate for everything else
     */
    fallback() external payable {
        address delegate = extensionDelegate;
        assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(gas(), delegate, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            switch result
            case 0 { revert(0, returndatasize()) }
            default { return(0, returndatasize()) }
        }
    }
}

File 8 of 12 : IAssetList.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometCore.sol";

/**
 * @title Compound's Asset List
 * @author Compound
 */
interface IAssetList {
    function getAssetInfo(uint8 i) external view returns (CometCore.AssetInfo memory);
    function numAssets() external view returns (uint8);
}

File 9 of 12 : IAssetListFactory.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;
import "./CometCore.sol";

/**
 * @title Compound's Asset List Factory
 * @author Compound
 */
interface IAssetListFactory {
    /**
     * @notice Create a new asset list
     * @param assetConfigs The asset configurations
     * @return assetList The address of the new asset list
     */
    function createAssetList(CometCore.AssetConfig[] memory assetConfigs) external returns (address assetList);
}

File 10 of 12 : IAssetListFactoryHolder.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title Compound's Asset List Factory Holder Interface
 * @author Compound
 */
interface IAssetListFactoryHolder {
    /**
     * @notice Get the asset list factory
     * @return assetListFactory The asset list factory address
     */
    function assetListFactory() external view returns (address);
}

File 11 of 12 : IERC20NonStandard.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title IERC20NonStandard
 * @dev Version of ERC20 with no return values for `approve`, `transfer`, and `transferFrom`
 *  See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
 */
interface IERC20NonStandard {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
     * @param spender The address of the account which may transfer tokens
     * @param amount The number of tokens that are approved (-1 means infinite)
     */
    function approve(address spender, uint256 amount) external;

    /**
     * @notice Transfer `value` tokens from `msg.sender` to `to`
     * @param to The address of the destination account
     * @param value The number of tokens to transfer
     */
    function transfer(address to, uint256 value) external;

    /**
     * @notice Transfer `value` tokens from `from` to `to`
     * @param from The address of the source account
     * @param to The address of the destination account
     * @param value The number of tokens to transfer
     */
    function transferFrom(address from, address to, uint256 value) external;

    /**
     * @notice Gets the balance of the specified address
     * @param account The address from which the balance will be retrieved
     */
    function balanceOf(address account) external view returns (uint256);
}

File 12 of 12 : IPriceFeed.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @dev Interface for price feeds used by Comet
 * Note This is Chainlink's AggregatorV3Interface, but without the `getRoundData` function.
 */
interface IPriceFeed {
  function decimals() external view returns (uint8);

  function description() external view returns (string memory);

  function version() external view returns (uint256);

  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1,
    "details": {
      "yulDetails": {
        "optimizerSteps": "dhfoDgvulfnTUtnIf [xa[r]scLM cCTUtTOntnfDIul Lcul Vcul [j] Tpeul xa[rul] xa[r]cL gvif CTUca[r]LsTOtfDnca[r]Iulc] jmul[jul] VcTOcul jmul"
      }
    }
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"components":[{"internalType":"address","name":"governor","type":"address"},{"internalType":"address","name":"pauseGuardian","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"baseTokenPriceFeed","type":"address"},{"internalType":"address","name":"extensionDelegate","type":"address"},{"internalType":"uint64","name":"supplyKink","type":"uint64"},{"internalType":"uint64","name":"supplyPerYearInterestRateSlopeLow","type":"uint64"},{"internalType":"uint64","name":"supplyPerYearInterestRateSlopeHigh","type":"uint64"},{"internalType":"uint64","name":"supplyPerYearInterestRateBase","type":"uint64"},{"internalType":"uint64","name":"borrowKink","type":"uint64"},{"internalType":"uint64","name":"borrowPerYearInterestRateSlopeLow","type":"uint64"},{"internalType":"uint64","name":"borrowPerYearInterestRateSlopeHigh","type":"uint64"},{"internalType":"uint64","name":"borrowPerYearInterestRateBase","type":"uint64"},{"internalType":"uint64","name":"storeFrontPriceFactor","type":"uint64"},{"internalType":"uint64","name":"trackingIndexScale","type":"uint64"},{"internalType":"uint64","name":"baseTrackingSupplySpeed","type":"uint64"},{"internalType":"uint64","name":"baseTrackingBorrowSpeed","type":"uint64"},{"internalType":"uint104","name":"baseMinForRewards","type":"uint104"},{"internalType":"uint104","name":"baseBorrowMin","type":"uint104"},{"internalType":"uint104","name":"targetReserves","type":"uint104"},{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint64","name":"borrowCollateralFactor","type":"uint64"},{"internalType":"uint64","name":"liquidateCollateralFactor","type":"uint64"},{"internalType":"uint64","name":"liquidationFactor","type":"uint64"},{"internalType":"uint128","name":"supplyCap","type":"uint128"}],"internalType":"struct CometConfiguration.AssetConfig[]","name":"assetConfigs","type":"tuple[]"}],"internalType":"struct CometConfiguration.Configuration","name":"config","type":"tuple"}],"name":"clone","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x6080604081815260043610156200001557600080fd5b60009060e0908235821c632d526439146200002f57600080fd5b34620003b7576020936003198581360112620003b3576001600160401b039360043590858211620003af578136036102a08094820112620003ab576153b190818601918683108984111762000397576200040087398982526001600160a01b03976102c08301949089620000a660048401620003bb565b168c85015289620000ba60248401620003bb565b168985015289620000ce60448401620003bb565b1693606094858201528a620000e660648501620003bb565b1690608091828201528b620000fe60848601620003bb565b169360a09485830152836200011660a48301620003d5565b169560c09687840152846200012e60c48401620003d5565b1689840152846200014260e48401620003d5565b1661010084015284620001596101048401620003d5565b1661012084015284620001706101248401620003d5565b1661014084015284620001876101448401620003d5565b16610160840152846200019e6101648401620003d5565b1661018084015284620001b56101848401620003d5565b166101a084015284620001cc6101a48401620003d5565b166101c084015284620001e36101c48401620003d5565b166101e084015284620001fa6101e48401620003d5565b1661020084015284620002116102048401620003d5565b166102208401526001600160681b0380620002306102248501620003ea565b1661024085015280620002476102448501620003ea565b166102608501526200025d6102648401620003ea565b16610280840152610284820135906022190181121562000393570197602460048a0135990199848a116200039357888a0236038b136200039357968f9593918f999795938b6102e0928f9e9d9b8084015252019998955b888710620002e0578f8f8f8e8e038f84f0928315620002d557505191168152f35b9051903d90823e3d90fd5b90929496989a508d620002f98c9b939597999b620003bb565b1682528d6200030a828d01620003bb565b16908201528b8a013560ff811680910362000393578c8201528362000331838c01620003d5565b16828201528362000344848c01620003d5565b16838201528362000357868c01620003d5565b1685820152858a01356001600160801b03811690819003620003935788828192896001950152019a01960193918a999896979593918f620002b4565b8e80fd5b634e487b7160e01b8a52604160045260248afd5b8780fd5b8680fd5b8480fd5b8280fd5b35906001600160a01b0382168203620003d057565b600080fd5b35906001600160401b0382168203620003d057565b35906001600160681b0382168203620003d05756fe6103a0806040523462000a7c57620053b1803803809162000021828562000a97565b8339602082828101031262000a7c5781516001600160401b03811162000a7c576102a0818401838501031262000a7c5760405192620000636102a08562000a97565b6200007082820162000abb565b84526200008260208383010162000abb565b60208501526200009760408383010162000abb565b6040850152620000ac60608383010162000abb565b6060850152620000c160808383010162000abb565b6080850152620000d660a08383010162000ad0565b60a0850152620000eb60c08383010162000ad0565b60c08501526200010060e08383010162000ad0565b60e0850152620001166101008383010162000ad0565b6101008501526200012d6101208383010162000ad0565b610120850152620001446101408383010162000ad0565b6101408501526200015b6101608383010162000ad0565b610160850152620001726101808383010162000ad0565b610180850152620001896101a08383010162000ad0565b6101a0850152620001a06101c08383010162000ad0565b6101c0850152620001b76101e08383010162000ad0565b6101e0850152620001ce6102008383010162000ad0565b610200850152620001e56102208383010162000ae5565b610220850152620001fc6102408383010162000ae5565b610240850152620002136102608383010162000ae5565b6102608501528082016102800151926001600160401b03841162000a7c57808201601f858585010101121562000a7c57818301840151916001600160401b03831162000a8157604051946200026f60208560051b018762000a97565b8386526020860194838301602060e08702848487010101011162000a7c57828101820160200195915b602060e08702828487010101018710620009be5761028089018890526040808a0151905163313ce56760e01b81528a91602090829060049082906001600160a01b03165afa9081156200080f576000916200097c575b50601260ff821611620008ed576101a0820151670de0b6b3a76400006001600160401b03909116116200096a576018610280830151511162000958576102208201516001600160681b0316156200094657606082015160405163313ce56760e01b815290602090829060049082906001600160a01b03165afa9081156200080f57600091620008ff575b5060ff6008911603620008ed5781516001600160a01b0390811660809081526020840151821660a0526040840151821660c0526060840151821660e05283015116610100526101a08201516001600160401b039081166102205261032082905260ff909116600a0a81166102408190526101c083015190911661026052620f424011620008ed576102408051620f42409004610360526102208201516001600160681b039081166102c0526101e0808401516001600160401b039081166102809081526102008087015183166102a0529486015184166102e0526102608601519093166103005260a0850151811661012090815260c08601516301e13380908316819004831661014090815260e088015184168290048416610160908152610100808a015186168490048616610180908152948a015186166101a05291890151851683900485166101c0528801518416829004841690945290860151821604169092528201515160ff166103405251604051630e085c5b60e31b81529190602090839060049082906001600160a01b03165afa9182156200080f57600092620008a3575b50610280015190604051809263ba15b9d160e01b82526024820160206004840152815180915260206044840192019060005b8181106200081b57506020949284900392849250600091506001600160a01b03165af19081156200080f57600091620007ca575b50610380526040516148a762000b0a823960805181818161063801528181610d71015281816114110152611811015260a0518181816108780152610e77015260c05181818161081e01528181611390015281816115f90152818161187a01528181611932015281816126b301528181612f550152818161308d015281816138d801528181613d1c0152613dfd015260e051818181611a7001528181612818015281816142ac01526146c7015261010051818181610eb701526147ff01526101205181818161133e01526121a8015261014051818181610f55015281816121e4015261224e015261016051818181611064015261227e0152610180518181816111c6015261220b01526101a05181818161114e01526122b801526101c051818181610a27015281816122f4015261235e01526101e051818181610931015261238e015261020051818181610fe0015261231b0152610220518181816107ae015261468b015261024051818181610cf10152818161283e01528181612b950152818161431c01526146ff0152610260518181816113d00152612e300152610280518181816106ec015261207401526102a0518181816112020152611ffc01526102c05181818161118a0152611f6e01526102e051818181610aa101528181613b1e0152613e9c015261030051818181610b1c0152611a2001526103205181610adf01526103405181818161130101528181611d4d0152818161287501528181612a7e01526142da01526103605181612e570152610380518181816117b60152611c3601526148a790f35b6020813d60201162000806575b81620007e66020938362000a97565b810103126200080257620007fb915062000abb565b8162000582565b5080fd5b3d9150620007d7565b6040513d6000823e3d90fd5b825180516001600160a01b0390811686526020828101519091168187015260408083015160ff16908701526060808301516001600160401b039081169188019190915260808084015182169088015260a0808401519091169087015260c0918201516001600160801b03169186019190915287955060e090940193909201916001016200054e565b90916020823d602011620008e4575b81620008c16020938362000a97565b81010312620008e15750620008d96102809162000abb565b91906200051c565b80fd5b3d9150620008b2565b604051630456c65960e51b8152600490fd5b906020823d6020116200093d575b816200091c6020938362000a97565b81010312620008e1575060ff6200093560089262000afa565b915062000378565b3d91506200090d565b604051636e77247560e01b8152600490fd5b60405163df8153c760e01b8152600490fd5b6040516324dc918f60e11b8152600490fd5b906020823d602011620009b5575b81620009996020938362000a97565b81010312620008e15750620009ae9062000afa565b82620002ee565b3d91506200098a565b60e087868601031262000a7c5760405192620009dc60e08562000a97565b620009e78862000abb565b8452620009f76020890162000abb565b602085015262000a0a6040890162000afa565b604085015262000a1d6060890162000ad0565b606085015262000a306080890162000ad0565b608085015262000a4360a0890162000ad0565b60a085015260c0880151936001600160801b038516850362000a7c57602060e09282829760c08695015281520198019793505062000298565b600080fd5b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b0382119082101762000a8157604052565b51906001600160a01b038216820362000a7c57565b51906001600160401b038216820362000a7c57565b51906001600160681b038216820362000a7c57565b519060ff8216820362000a7c5756fe60806040526004361015610018575b6100166147f2565b005b60003560e01c8063042e02cf146105685780630902f1ac1461055f5780630bc47ad1146105565780630c340a241461054d57806318160ddd14610544578063189bb2f11461053b5780631c9f7fb9146105325780631f5954bd1461052957806323b872dd1461052057806324a3d62214610517578063264413181461050e5780632a48cf12146105055780632b92a07d146104fc5780632d05670b146104f35780632e04b8e7146104ea578063300e6beb146104e1578063313ce567146104d857806332176c49146104cf578063374c49b4146104c657806338aa813f146104bd5780633b3bec2e146104b457806341976e09146104ab5780634232cd63146104a2578063439e2e451461049957806344c1e5eb1461049057806344c35d071461048757806344ff241d1461047e57806359e017bd146104755780635a94b8d11461046c57806367800b5f1461046357806370a082311461045a5780637914acc7146104515780637ac88ed1146104485780637eb711311461043f578063804de71f146104365780638285ef401461042d5780638d5d814c14610424578063903231771461041b5780639241a561146104125780639364e18a1461040957806394920cca146104005780639ea99a5a146103f75780639fa83b5a146103ee5780639ff567f8146103e5578063a1654379146103dc578063a1a1ef43146103d3578063a46fe83b146103ca578063a5b4ff79146103c1578063a9059cbb146103b8578063aba7f15e146103af578063ad14777c146103a6578063bfe69c8d1461039d578063c1ee2c1814610394578063c3b35a7e1461038b578063c3cecfd214610382578063c55dae6314610379578063c5fa15cf14610370578063c8c7fe6b14610367578063cde680411461035e578063d8e5f61114610355578063d955759d1461034c578063dc4abafd14610343578063e372f03a1461033a578063e478795d14610331578063e4e6e77914610328578063e7dad6bd1461031f578063f2b9fdb8146103165763f3fef3a30361000e57610311611ad4565b61000e565b50610311611a9f565b50610311611a59565b506103116118d0565b506103116117e5565b5061031161179f565b5061031161172c565b5061031161170d565b506103116116e6565b506103116116ca565b506103116116a1565b50610311611628565b506103116115e2565b5061031161157d565b50610311611559565b50610311611533565b50610311611498565b506103116113f3565b506103116113b7565b50610311611361565b50610311611325565b506103116112e6565b506103116112bf565b5061031161127e565b50610311611256565b50610311611225565b506103116111e9565b506103116111ad565b50610311611171565b50610311611135565b5061031161110f565b506103116110e8565b50610311611087565b5061031161104b565b5061031161102f565b50610311611003565b50610311610fc7565b50610311610f9f565b50610311610f78565b50610311610f3c565b50610311610ee6565b50610311610ea0565b50610311610d21565b50610311610cd8565b50610311610cb4565b50610311610c90565b50610311610c68565b50610311610c33565b50610311610b67565b50610311610b3f565b50610311610b03565b50610311610ac4565b50610311610a88565b50610311610a4a565b50610311610a0e565b506103116109b9565b50610311610918565b506103116108de565b50610311610861565b506103116107fe565b50610311610795565b5061031161070f565b506103116106d3565b50610311610667565b50610311610621565b506103116105e8565b506103116105c4565b50610311610587565b6001600160a01b0381160361058257565b600080fd5b50346105825760203660031901126105825760206105af6004356105aa81610571565b612a35565b6040519015158152f35b600091031261058257565b50346105825760003660031901126105825760206105e0612661565b604051908152f35b50346105825760003660031901126105825760206001805460f81c161515604051908152f35b6001600160a01b03909116815260200190565b5034610582576000366003190112610582576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461058257600036600319011261058257602066038d7ea4c680006106ca61068e611dbe565b6106b1600154916106ab64ffffffffff91828560d01c1690611e49565b166120fd565b506001600160401b0316906001600160681b0316611e77565b04604051908152f35b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610582576000806003193601126107925760015464ffffffffff8160d01c166107815764ffffffffff60d01b610745611dbe565b64ffffffffff60d01b1990921660d09290921b161760015580546001600160801b0319166e038d7ea4c6800000038d7ea4c68000178155604051f35b60405162dc149f60e41b8152600490fd5b80fd5b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b908160609103126105825780356107e781610571565b91604060208301356107f881610571565b92013590565b5034610582576108446108123660046107d1565b919061081c612fd5565b7f000000000000000000000000000000000000000000000000000000000000000091336138a0565b600060008051602061485283398151915255602060405160018152f35b5034610582576000366003190112610582576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b91908260809103126105825781356108be81610571565b9160208101356108cd81610571565b91606060408301356107f881610571565b5034610582576109046108f23660046108a7565b926108fe929192612fd5565b33613ced565b600060008051602061485283398151915255005b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b9190826040910312610582576020823561096d81610571565b92013561097981610571565b90565b9060018060a01b0316600052602052604060002090565b6001600160801b031690565b6001600160801b0391821681529116602082015260400190565b503461058257610a0a6109ee6109d0366004610954565b6001600160a01b03909116600090815260066020526040902061097c565b54604051918291608081901c906001600160801b03168361099f565b0390f35b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461058257602036600319011261058257600435610a6881610571565b60018060a01b031660005260046020526020604060002054604051908152f35b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461058257600036600319011261058257602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346105825760203660031901126105825760206105e0600435610b6281610571565b6147aa565b50346105825760203660031901126105825760206105af600435610b8a81610571565b6127b4565b6001600160401b031690565b610c319092919260e08061010083019560ff815116845260018060a01b03806020830151166020860152604082015116604085015260018060401b036060820151166060850152610bfb6080820151608086019060018060401b03169052565b60a0818101516001600160401b03169085015260c0818101516001600160401b03169085015201516001600160801b0316910152565b565b503461058257602036600319011261058257610a0a610c5c600435610c5781610571565b611d3a565b60405191829182610b9b565b50346105825760203660031901126105825760206105e0600435610c8b81610571565b61249f565b503461058257610904610ca43660046107d1565b91610cad612fd5565b3333612f23565b503461058257610904610cc83660046107d1565b91610cd1612fd5565b33336138a0565b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3590811515820361058257565b50346105825760a036600319011261058257610d3d6004610d14565b610d476024610d14565b610d516044610d14565b91610d5c6064610d14565b92610d676084610d14565b60018060a01b03807f0000000000000000000000000000000000000000000000000000000000000000163314159081610e73575b50610e62577f3be39979091ae7ca962aa1c44e645f2df3c221b79f324afa5f44aedc8d2f690d94610e5d92610e28610de56000610dd788612b6e565b9060ff8080931691161b1690565b610df36001610dd78a612b6e565b17610e026002610dd785612b6e565b17610e116003610dd786612b6e565b17610e206004610dd787612b6e565b176001612b4b565b6040519586958693909594919260809360a0860197151586521515602086015215156040850152151560608401521515910152565b0390a1005b6040516282b42960e81b8152600490fd5b90507f00000000000000000000000000000000000000000000000000000000000000001633141538610d9b565b5034610582576000366003190112610582576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461058257602036600319011261058257600435610f0481610571565b6001600160a01b031660009081526002602052604090819020549051908190610a0a90608081901c906001600160801b03168361099f565b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610582576000366003190112610582576020600460015460f81c161515604051908152f35b50346105825760203660031901126105825760206105e0600435610fc281610571565b61474c565b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346105825760403660031901126105825760206105e060043561102681610571565b6024359061462d565b50346105825760003660031901126105825760206105e06123ec565b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461058257600036600319011261058257602066038d7ea4c680006106ca6110ae611dbe565b6110cb600154916106ab64ffffffffff91828560d01c1690611e49565b6001600160401b03169160681c6001600160681b03169050611e77565b5034610582576000366003190112610582576020600860015460f81c161515604051908152f35b5034610582576109046111233660046108a7565b9261112f929192612fd5565b33612f23565b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346105825760203660031901126105825760206112446004356122b6565b6040516001600160401b039091168152f35b50346105825760203660031901126105825760206105e060043561127981610571565b612559565b503461058257602060ff6112b3611296366004610954565b6001600160a01b039091166000908152600385526040902061097c565b54166040519015158152f35b5034610582576000366003190112610582576020600260015460f81c161515604051908152f35b503461058257600036600319011261058257602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346105825760403660031901126105825761084460043561138281610571565b61138a612fd5565b602435907f00000000000000000000000000000000000000000000000000000000000000009033336138a0565b50346105825760003660031901126105825760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610582576114043660046107d1565b91906001600160a01b03907f000000000000000000000000000000000000000000000000000000000000000082163303610e62571691823b1561058257611465926000928360405180968195829463095ea7b360e01b845260048401613ed6565b03925af1801561148b575b61147657005b80611485600061001693611b46565b806105b9565b611493611bfe565b611470565b5034610582576020366003190112610582576100166004356114b981610571565b6114c1611ece565b60018060a01b03811660005260056020526040600020611528604051916114e960a084611b46565b54600c81900b83526001600160401b03606882901c8116602085015260a882901c16604084015261ffff60e882901c16606084015260f81c6080830152565b8051600c0b91612db5565b5034610582576109046115473660046108a7565b92611553929192612fd5565b336138a0565b50346105825761090461156d3660046107d1565b91611576612fd5565b3333613ced565b50346105825760403660031901126105825760043561159b81610571565b602435906001600160401b03908183116105825736602384011215610582578260040135918211610582573660248360051b85010111610582576024610016930190614118565b5034610582576000366003190112610582576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105825760203660031901126105825760043561164681610571565b60018060a01b0316600052600760205260806040600020546040519063ffffffff8116825260018060401b038160201c166020830152600180841b038160601c16604083015260e01c6060820152f35b60ff81160361058257565b503461058257602036600319011261058257610a0a610c5c6004356116c581611696565b611c0b565b50346105825760206105af6116e0366004610954565b90611b09565b5034610582576000366003190112610582576020601060015460f81c161515604051908152f35b50346105825760203660031901126105825760206112446004356121a6565b50346105825760203660031901126105825760043561174a81610571565b60018060a01b0316600052600560205260a06040600020546040519080600c0b825260018060401b03808260681c1660208401528160a81c16604083015261ffff8160e81c16606083015260f81c6080820152f35b5034610582576000366003190112610582576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105825760403660031901126105825760043561180381610571565b602435906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081163303610e6257611840612661565b600081129081156118be575b506118ac578161189e847fec4431f2ba1a9382f6b0c4352b888cba6f7db91667d9f776abe5ad8ddc5401b6947f0000000000000000000000000000000000000000000000000000000000000000613ef1565b6040519384521691602090a2005b60405163128bd24d60e31b8152600490fd5b6118c89150614622565b83113861184c565b5034610582576080366003190112610582576004356118ee81610571565b606435906118fb82610571565b611903612fd5565b601060015460f81c16611a4757611918612661565b60008112159081611a1c575b50611a0a57611956604435337f00000000000000000000000000000000000000000000000000000000000000006133d8565b90611961828261462d565b9260243584106119f85761197482612559565b84116118ac577ff891b2a411b0e66a5f0a6ff1368670fefa287a13f541eb633a386a1a9cc7046b916119bb6119de926119b46119af88612faf565b610993565b9083613ef1565b6040805194855260208501959095526001600160a01b0316933393918291820190565b0390a3610016600060008051602061485283398151915255565b60405163fa6ad35560e01b8152600490fd5b604051631d99ddbf60e01b8152600490fd5b90507f0000000000000000000000000000000000000000000000000000000000000000111538611924565b6040516313d0ff5960e31b8152600490fd5b5034610582576000366003190112610582576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461058257604036600319011261058257610904600435611ac081610571565b611ac8612fd5565b60243590333333612f23565b503461058257604036600319011261058257610904600435611af581610571565b611afd612fd5565b60243590333333613ced565b6001600160a01b03808316911690811491908215611b2657505090565b60ff925090611b41916000526003602052604060002061097c565b541690565b601f909101601f19168101906001600160401b03821190821017611b6957604052565b634e487b7160e01b600052604160045260246000fd5b60405190611b8f61010083611b46565b8160e06000918281528260208201528260408201528260608201528260808201528260a08201528260c08201520152565b5190610c3182611696565b5190610c3182610571565b51906001600160401b038216820361058257565b51906001600160801b038216820361058257565b506040513d6000823e3d90fd5b611c13611b7f565b5060405163c8c7fe6b60e01b815260ff91909116600482015261010080826024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa918215611d2d575b600092611c7457505090565b90918282813d8311611d26575b611c8b8183611b46565b81010312610792575060e0611d1e91611ca76040519485611b46565b611cb081611bc0565b8452611cbe60208201611bcb565b6020850152611ccf60408201611bcb565b6040850152611ce060608201611bd6565b6060850152611cf160808201611bd6565b6080850152611d0260a08201611bd6565b60a0850152611d1360c08201611bd6565b60c085015201611bea565b60e082015290565b503d611c81565b611d35611bfe565b611c68565b90611d43611b7f565b5060009060ff92837f000000000000000000000000000000000000000000000000000000000000000016925b8385821610611d8a57604051633640530560e01b8152600490fd5b611d9381611c0b565b60208101516001600160a01b03848116911614611db557506001018416611d6f565b93505050915090565b600160281b421015611dd55764ffffffffff421690565b604051633d32ffdb60e01b8152600490fd5b90604051611df660a082611b46565b608081935480600c0b835260018060401b03808260681c1660208501528160a81c16604084015261ffff8160e81c16606084015260f81c910152565b50634e487b7160e01b600052601160045260246000fd5b64ffffffffff9182169116818110611e5f570390565b611e67611e32565b0390565b6001600160681b031690565b8060001904821181151516611e8a570290565b611e92611e32565b0290565b6001600160401b0391821691908116908290038111611eb3570190565b611ebb611e32565b0190565b60681c6001600160681b031690565b611ed6611dbe565b611f00611ef6611ef060015464ffffffffff9060d01c1690565b83611e49565b64ffffffffff1690565b9081611f0a575050565b81611f61611f1a610c31946120fd565b60008054600160401b600160801b03191660409290921b600160401b600160801b0316919091178155919082546001600160401b0319166001600160401b03909116178255565b611f6c600154611e6b565b7f000000000000000000000000000000000000000000000000000000000000000092906001600160681b031683811015612061575b50611fb5611fb0600154611ebf565b611e6b565b92831015611fe9575b50506001805464ffffffffff60d01b191660d09390931b64ffffffffff60d01b169290921790915550565b61202a61202561205994612020612039947f0000000000000000000000000000000000000000000000000000000000000000611e77565b612b8f565b6120d7565b825460c01c611e96565b611e96565b81546001600160c01b031660c09190911b6001600160c01b031916179055565b388080611fbe565b6120ab6120986120256120d193612020867f0000000000000000000000000000000000000000000000000000000000000000611e77565b845460801c6001600160401b0316611e96565b8354600160801b600160c01b03191660809190911b600160801b600160c01b0316178355565b38611fa1565b6001600160401b03908181116120eb571690565b6040516372a1cb5160e11b8152600490fd5b6000546001600160401b03604082901c81169392918116919081612122575b50509190565b8161217561216f61214f97946121816121879761217b8761215661217b996121486123ec565b9e8f6121a6565b169d6122b6565b169b61217561216f670de0b6b3a7640000998a93611e77565b84611e77565b046120d7565b90611e96565b98611e77565b91388061211c565b81198111611eb3570190565b818110611e5f570390565b7f000000000000000000000000000000000000000000000000000000000000000080821161222f5750612025670de0b6b3a7640000612208610979937f0000000000000000000000000000000000000000000000000000000000000000611e77565b047f000000000000000000000000000000000000000000000000000000000000000061218f565b61097991612025916122a2670de0b6b3a76400009161227283612208837f0000000000000000000000000000000000000000000000000000000000000000611e77565b938181106122a9575b037f0000000000000000000000000000000000000000000000000000000000000000611e77565b049061218f565b6122b1611e32565b61227b565b7f000000000000000000000000000000000000000000000000000000000000000080821161233f5750612025670de0b6b3a7640000612318610979937f0000000000000000000000000000000000000000000000000000000000000000611e77565b047f000000000000000000000000000000000000000000000000000000000000000061218f565b61097991612025916122a2670de0b6b3a76400009161238283612318837f0000000000000000000000000000000000000000000000000000000000000000611e77565b938181106123b2575b037f0000000000000000000000000000000000000000000000000000000000000000611e77565b6123ba611e32565b61238b565b50634e487b7160e01b600052601260045260246000fd5b81156123e0570490565b6123e86123bf565b0490565b60005460015466038d7ea4c680009061242e906001600160681b036001600160401b038461241e828816848616611e77565b049560401c169160681c16611e77565b048161243b575050600090565b670de0b6b3a764000090806000190482118115151661245957020490565b612461611e32565b020490565b66038d7ea4c68000916123e8916001600160401b0316906001600160681b0316611e77565b51906001600160501b038216820361058257565b604051633fabe5a360e21b81529060a090829060049082906001600160a01b03165afa90811561253d575b6000916124f1575b5060008113156124df5790565b60405163fd1ee34960e01b8152600490fd5b9060a0823d8211612535575b8161250a60a09383611b46565b81010312610792575061251c8161248b565b5061252e60806020830151920161248b565b50386124d2565b3d91506124fd565b612545611bfe565b6124ca565b90816020910312610582575190565b6040516370a0823160e01b8152306004820152906001600160a01b0316602082602481845afa9182156125e4575b6000926125b4575b506000908152600260205260409020546001600160801b031690818110611e5f570390565b6125d691925060203d81116125dd575b6125ce8183611b46565b81019061254a565b903861258f565b503d6125c4565b6125ec611bfe565b612587565b600082128015600160ff1b840183121661261b575b6001600160ff1b038301821316611e5f570390565b612623611e32565b612606565b6000811280156001600160ff1b03839003841316612654575b600160ff1b829003831216611eb3570190565b61265c611e32565b612641565b61097961266c611dbe565b61268f61268a611ef66001549364ffffffffff8560d01c1690611e49565b6120fd565b90604051926370a0823160e01b8452602084806126af306004830161060e565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa938415612784575b60009461274c575b509161274061273a61273a936127336127469666038d7ea4c680009260018060401b03846127268260018060681b039416848616611e77565b0497169160681c16611e77565b0495612791565b91612791565b906125f1565b90612628565b6127469391945061273a61273a936127336127776127409460203d81116125dd576125ce8183611b46565b97949650509350506126ed565b61278c611bfe565b6126e5565b6001600160ff1b0381116127a25790565b60405163e7e828ad60e01b8152600490fd5b6127c96127c282600561097c565b54600c0b90565b906000918281600c0b1215612981576127f16127e683600561097c565b5460e81c61ffff1690565b9061286c61281361280d61280686600561097c565b5460f81c90565b926129c0565b61283c7f000000000000000000000000000000000000000000000000000000000000000061249f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160401b031691612bda565b92849160ff93847f000000000000000000000000000000000000000000000000000000000000000016935b84868216106128ab57505050505050121590565b6128b6838284612cc0565b6128c5575b6001018516612897565b958781121561297457600161296b87926127466129668861296061295b60808f6129236129166129026128fa61295394611c0b565b97600661097c565b60208801516001600160a01b03169061097c565b546001600160801b031690565b604086015161293a906001600160a01b031661249f565b6129476060880151610b8f565b918c80861b0316612bba565b930151610b8f565b610b8f565b90612b7c565b612791565b979150506128bb565b5050505050505050600190565b505050600190565b600c0b6001600160671b031981146129a2575b60000390565b6129aa611e32565b61299c565b600160ff1b81146129a25760000390565b6000600c82900b12612a00576000546109799166038d7ea4c68000916129fa916001600160401b03909116906001600160681b0316611e77565b04612791565b612a3061296661097992612a2160018060401b0360005460401c1691612989565b6001600160681b031690612466565b6129af565b612a436127c282600561097c565b906000918281600c0b1215612b4657612a606127e683600561097c565b90612a7561281361280d61280686600561097c565b92849160ff93847f000000000000000000000000000000000000000000000000000000000000000016935b8486821610612ab3575050505050501290565b612abe838284612cc0565b612acd575b6001018516612aa0565b9587811215612b3c576001612b3387926127466129668861296061295b60a08f612b026129166129026128fa61295394611c0b565b6040860151612b19906001600160a01b031661249f565b612b266060880151610b8f565b918c8060801b0316612bba565b97915050612ac3565b5050505050505090565b505090565b80546001600160f81b031660f89290921b6001600160f81b031916919091179055565b600090156109795750600190565b670de0b6b3a7640000916123e891611e77565b6123d6907f000000000000000000000000000000000000000000000000000000000000000090611e77565b90612bc491611e77565b6001600160401b039091169081156123e0570490565b9190612be590612791565b6000808413939082136001600160ff1b03858216848204841116612ca1575b600160ff1b95600085129185918316858905831216612c94575b60008512938416828905861216612c87575b058312911616612c7a575b6001600160401b03909216929102908215612c6d575b8114600019831416612c61570590565b612c69611e32565b0590565b612c756123bf565b612c51565b612c82611e32565b612c3b565b612c8f611e32565b612c30565b612c9c611e32565b612c1e565b612ca9611e32565b612c04565b60ff9182169116818110611e5f570390565b9060ff169160108310600014612cdf5750600161ffff921b1616151590565b905060188210612cf0575050600090565b600160ff8093600f1901161b1616151590565b6001600160401b039182169116818110611e5f570390565b805461ffff60e81b191660e89290921b61ffff60e81b16919091179055565b81518154602084015160408501516001600160e81b03199092166001600160681b039093169290921760689290921b600160681b600160a81b03169190911760a89190911b600160a81b600160e81b03161781556060820151610c319260ff9160809190612dac9061ffff1685612d1b565b01511690612b4b565b612ecc90610c3193612dc88451600c0b90565b600c82900b855260009182918683600c83900b8113612ee357612e55612e2e612e9b94612e1f61295b612e7c96612e196020612e11612025995460018060401b039060801c1690565b920151610b8f565b90612d03565b906001600160681b0316611e77565b7f0000000000000000000000000000000000000000000000000000000000000000906123d6565b7f0000000000000000000000000000000000000000000000000000000000000000906123d6565b612e8e60408901916120348351610b8f565b6001600160401b03169052565b600c0b12612ed15754612ec59060801c6001600160401b03165b6001600160401b03166020850152565b600561097c565b612d3a565b54612ede9060c01c612eb5565b612ec5565b612e55612e2e612f1e94612f19611fb0611e6b612f1361295b612e7c99612e196020612e116120259c5460c01c90565b93612989565b611e77565b612e9b565b939290936001805460f81c16611a4757612f40612f449186611b09565b1590565b610e62576001600160a01b038181167f000000000000000000000000000000000000000000000000000000000000000090911603612f9b5750610c31926000198303613082579150612f95816147aa565b91613082565b90612fa9610c319493612faf565b926135fc565b6001600160801b0390818111612fc3571690565b60405163762ea71160e11b8152600490fd5b6000805160206148528339815191526001815414612ff35760019055565b60405163139b643560e21b8152600490fd5b6001600160681b0391821691908116908290038111611eb3570190565b80546001600160681b0319166001600160681b03909216919091179055565b6001600160681b039182169116818110611e5f570390565b8054600160681b600160d01b03191660689290921b600160681b600160d01b0316919091179055565b6130b161312f9293827f00000000000000000000000000000000000000000000000000000000000000006133d8565b6130b9611ece565b61313c6130cf6130ca86600561097c565b611de7565b8051600c0b906131366130ff6130f86130f36130ea866129c0565b61274689612791565b6131c6565b809461335c565b979061311f6131188a613113600154611e6b565b613005565b6001613022565b61312a600154611ebf565b613041565b6001613059565b86612db5565b6040519081526001600160a01b0393841693849216907fd1cf3d156d5f8f0d50f6c122ed609cec09d35c9b9fb3fff6ea0959134dae424e90602090a36001600160681b03811661318a575050565b6000805160206148328339815191526131c16131b16000936131ac8554610b8f565b612466565b6040519081529081906020820190565b0390a3565b600081126131ec57600054610979916131e7916001600160401b0316613275565b6132eb565b6132496131e76109799261320d60018060401b0360005460401c16916129af565b613232826000199266038d7ea4c6800090808504821181151516613268575b0261218f565b6001811061325b575b821561324e575b01046132c5565b612989565b6132566123bf565b613242565b613263611e32565b61323b565b613270611e32565b61322c565b906109799166038d7ea4c680009082600019048211831515166132b8575b6001600160401b03169182156132ab575b02046132c5565b6132b36123bf565b6132a4565b6132c0611e32565b613293565b6001600160681b03908181116132d9571690565b604051630dc7925560e11b8152600490fd5b6001600160681b03166001600160671b03811161330857600c0b90565b604051639369ae3560e01b8152600490fd5b600c91820b910b6000821280156001600160671b0319840183121661334f575b6001600160671b038301821316611e5f570390565b613357611e32565b61333a565b91909180600c0b83600c0b8181126133cb5760001261338f5750613380919261331a565b6001600160681b031690600090565b6000136133b2576133a0919261331a565b6000916001600160681b039190911690565b6133bb90612989565b6001600160681b03908116921690565b5050509050600090600090565b6040516370a0823160e01b8082529390926020926001600160a01b03169190838580613407306004830161060e565b0381865afa948515613545575b600095613526575b50823b15610582576040516323b872dd60e01b81526001600160a01b03919091166004820152306024820152604481019190915260008160648183865af18015613519575b613504575b503d80156134fb5760201461347a57600080fd5b816000803e6000515b156134e9578161097994604051928391825281806134a4306004830161060e565b03915afa9182156134dc575b6000926134bf575b505061219b565b6134d59250803d106125dd576125ce8183611b46565b38806134b8565b6134e4611bfe565b6134b0565b60405163073d1efd60e51b8152600490fd5b50600019613483565b80611485600061351393611b46565b38613466565b613521611bfe565b613461565b61353e919550843d86116125dd576125ce8183611b46565b933861341c565b61354d611bfe565b613414565b90604051613561604082611b46565b91546001600160801b038116835260801c6020830152565b6001600160801b0391821691908116908290038111611eb3570190565b80546001600160801b0319166001600160801b03909216919091179055565b90602060018060801b03916135cd8382511685613596565b0151825490911660809190911b6001600160801b031916179055565b6001600160801b03909116815260200190565b91909261361b61361660018060801b0380931685856133d8565b612faf565b9161362581611d3a565b9061363961363482600261097c565b613552565b9261365d6136508661364b8751610993565b613579565b6001600160801b03168552565b6136678451610993565b906136786119af60e0860151610993565b911611613722576136fd6136eb8561371d946136f77ffa56f7b24f17183d81894d3ac2ee654e3c26388d17a28dbd9549b8114304e1f4976136f2876136cc8e6136d86136d1612916856136cc85600661097c565b61097c565b9889613579565b9889956136e685600261097c565b6135b5565b600661097c565b613596565b89613734565b6040516001600160a01b03918216968216959091169390918291826135e9565b0390a4565b604051637ac7b99d60e11b8152600490fd5b909290916001600160801b03908116158080613895575b156137f15750505061375e825160ff1690565b60ff811660108110156137b0575050613798613790613781610c31945160ff1690565b600160ff9091161b61ffff1690565b91600561097c565b906137a9825461ffff9060e81c1690565b1790612d1b565b6018919350106137be575050565b6137de6137906137d26010610c3195612cae565b600160ff9182161b1690565b906137ea825460f81c90565b1790612b4b565b15918261388a575b5050613803575050565b815160ff1680601081101561384b57505061383361379061382b613781610c31955160ff1690565b1961ffff1690565b90613844825461ffff9060e81c1690565b1690612d1b565b601891935010613859575050565b6138776137906138706137d26010610c3196612cae565b1960ff1690565b90613883825460f81c90565b1690612b4b565b1615905038806137f9565b50818316151561374b565b93929093600260015460f81c16611a4757612f406138be9186611b09565b610e62576001600160a01b038481168382161461393657807f000000000000000000000000000000000000000000000000000000000000000016908216146000146139225750610c3192600019830361394857915061391c8261474c565b91613948565b90613930610c319493612faf565b92613be1565b60405163e397a99b60e01b8152600490fd5b919091613953611ece565b61395e81600561097c565b61396790611de7565b61397284600561097c565b61397b90611de7565b92815161398890600c0b90565b93805161399590600c0b90565b9261399f866129c0565b6139a884612791565b6139b1916125f1565b926139bb856129c0565b906139c590612791565b6139ce91612628565b906139d8846131c6565b6139e281936131c6565b9788936139ee91613b7c565b986139f9919761335c565b98878a600154613a0890611e6b565b90613a1291613005565b90613a1c91613041565b613a27906001613022565b600154613a3390611ebf565b90613a3d91613005565b90613a4791613041565b613a52906001613059565b613a5c9187612db5565b613a669187612db5565b60008112613b13575b506001600160681b0391818316613acb575b50508116613a8d575050565b6000805160206148328339815191526131c1613aaf6000936131ac8554610b8f565b6040519081526001600160a01b03909416939081906020820190565b600080516020614832833981519152613b09613aed6000946131ac8654610b8f565b6040519081526001600160a01b03909316929081906020820190565b0390a33880613a81565b613b1c906129af565b7f000000000000000000000000000000000000000000000000000000000000000011613b6a57613b4e612f40836127b4565b613b585738613a6f565b604051630a62fbdb60e11b8152600490fd5b604051637139da2360e11b8152600490fd5b919082600c0b81600c0b8181136133cb57600013613b9f5750613380919261331a565b600012613bb0576133a0919261331a565b613bb990612989565b6001600160681b03928316921690565b6001600160801b039182169116818110611e5f570390565b6001600160a01b0380821660008181526006602052604090206001600160801b03959194919391908690613c1690869061097c565b54168382169687600052600660205285604060002090613c359161097c565b5416613c418983613bc9565b613c4b8a83613579565b928188613c5988600661097c565b90613c639161097c565b90613c6d91613596565b8388613c7a87600661097c565b90613c849161097c565b90613c8e91613596565b613c9788611d3a565b91613ca3918388613734565b613cac93613734565b613cb5906127b4565b15613b58577f29db89d45e1a802b4d55e202984fce9faf1d30aedf86503ff1ea0ed9ebb642019161371d6040519283921696826135e9565b93929093600460015460f81c16611a4757612f40613d0b9186611b09565b610e62576001600160a01b038181167f000000000000000000000000000000000000000000000000000000000000000090911603613d625750610c31926000198303613d76579150613d5c8261474c565b91613d76565b90613d70610c319493612faf565b92613f99565b909161312f92613d84611ece565b613d926130ca84600561097c565b613dec613da08251600c0b90565b613db5613dac826129c0565b61274087612791565b92613136613dcc613dc5866131c6565b8094613b7c565b613de16131188361312a60019e959e54611e6b565b613113600154611ebf565b60008112613e91575b50613e2182827f0000000000000000000000000000000000000000000000000000000000000000613ef1565b6040519182526001600160a01b0392831692169082907f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb90602090a36001600160681b038216613e6f575050565b6000805160206148328339815191526131c16131b16000946131ac8654610b8f565b613e9a906129af565b7f000000000000000000000000000000000000000000000000000000000000000011613b6a57613ecc612f40846127b4565b613b585738613df5565b6001600160a01b039091168152602081019190915260400190565b6001600160a01b03169291833b1561058257613f2b90604051809581809563a9059cbb60e01b825260009889968796879360048401613ed6565b03925af18015613f8c575b613f7c575b503d90508015613f7157602014613f50575080fd5b90602081803e515b15613f5f57565b60405163cefaffeb60e01b8152600490fd5b509050600019613f58565b613f8591611b46565b3882613f3b565b613f94611bfe565b613f36565b6001600160a01b038082166000818152600660205260408120909695919491936001600160801b03918290613fcf90879061097c565b5416613fdb8882613bc9565b80878781169b8c81526002602052604081208c8882541690613ffc91613bc9565b61400591613596565b8a81526006602052604090209061401b9161097c565b9061402591613596565b61402e87611d3a565b916140399284613734565b614042906127b4565b15613b58577fd6d480d5b3068db003533b170d67561494d72e3bf9fa40a266471351ebba9e16938261407692881691613ef1565b61371d6040519283921695826135e9565b91908110156140975760051b0190565b634e487b7160e01b600052603260045260246000fd5b3561097981610571565b906040516140c6608082611b46565b915463ffffffff81168352602081811c6001600160401b031690840152606081811c6001600160801b0316604085015260e09190911c90830152565b60019063ffffffff809116908114611eb3570190565b9291909260016008815460f81c16611a47575a94614134611ece565b60005b84811061422e575050506141d9906141d26141b361361661415d610c3197985a9061219b565b6141ac61419a61417661417188600761097c565b6140b7565b9861202561419061418b8c5163ffffffff1690565b614102565b63ffffffff168b52565b612e8e60208a01916120348351610b8f565b4890611e77565b6141c5604086019161364b8351610993565b6001600160801b03169052565b600761097c565b815160208084015160408501516060958601516001600160e01b031960e09190911b16600160601b600160e01b039190961b1663ffffffff909316600160201b600160601b039190921b161717919091179055565b8061424c61424661424186948987614087565b6140ad565b86614252565b01614137565b9061425f612f4082612a35565b6145e7576142716130ca82600561097c565b9061427d8251600c0b90565b90614287826129c0565b91614297606085015161ffff1690565b906142a6608086015160ff1690565b936142d07f000000000000000000000000000000000000000000000000000000000000000061249f565b92600095865b60ff7f00000000000000000000000000000000000000000000000000000000000000001660ff82161061448f5750505061434e6143486129668561434360018060401b037f000000000000000000000000000000000000000000000000000000000000000016809a611e77565b6123d6565b82612628565b9160008312614486575b614361836131c6565b968761436d9187612db5565b61437885600561097c565b600061438391612d1b565b8661438f86600561097c565b600061439a91612b4b565b6143a39161335c565b6001546143af90611e6b565b906143b991613005565b6143c4906001613022565b6001546143d090611ebf565b906143da91613041565b6143e5906001613059565b6143ee916125f1565b6143f790614622565b926144029184612bba565b6040805193845260208401919091526001600160a01b039182169485939216917f1547a878dc89ad3c367b6338b4be6a65a5dd74fb77ae044da1e8747ef1f4f62f9190a380600c0b600012614455575050565b6000805160206148328339815191526131c16131b160009361448061447a8654610b8f565b916145f9565b90612466565b60009250614358565b61449a828285612cc0565b6144aa575b60010160ff166142d6565b868a6144b583611c0b565b602081015183906001600160a01b03169b8c6006816144d4858361097c565b906144de9161097c565b546001600160801b0316936144f29161097c565b906144fc9161097c565b600061450791613596565b6145128d600261097c565b82815461451e90610993565b9061452891613bc9565b61453191613596565b60408301516001600160a01b03166145489061249f565b606084015161455690610b8f565b614569916001600160801b038516612bba565b9260c0015161457790610b8f565b61458090610b8f565b61458a9084612b7c565b6145939161218f565b604080516001600160801b0393909316835260208301939093529b6001600160a01b039081169481169316917f9850ab1af75177e4a9201c65a2cf7976d5d28e40ef63494b44366f86b2f9412e91a461449f565b604051636ef5bcdd60e11b8152600490fd5b600081600c0b12614610576001600160681b031690565b60405163363b64b760e11b8152600490fd5b600081126146105790565b906146f561463d61097993611d3a565b6146c060606146eb61465a60018060a01b0360408601511661249f565b60c08501516001600160401b0394670de0b6b3a764000092909183906146af908890811680841061473f575b8303167f0000000000000000000000000000000000000000000000000000000000000000611e77565b04808410614732575b830390611e77565b0495612f197f000000000000000000000000000000000000000000000000000000000000000061249f565b9201511690611e77565b908015614725575b7f000000000000000000000000000000000000000000000000000000000000000091046123d6565b61472d6123bf565b6146fd565b61473a611e32565b6146b8565b614747611e32565b614686565b61476f614757611dbe565b6106ab64ffffffffff918260015460d01c1690611e49565b506001600160a01b03909116600090815260056020526040812054600c0b9190808313156147a45750614480610979926145f9565b91505090565b6147b5614757611dbe565b6001600160a01b03909216600090815260056020526040812054600c0b929150808312156147a457506144806147ed61097993612989565b6145f9565b50600036818037808036817f00000000000000000000000000000000000000000000000000000000000000005af43d82803e1561482d573d90f35b3d90fdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efc98c7730ba19013824f711a9ab74801459b27e6ff7685cb924587c89aeda53aca2646970667358221220dd4d8e5db53112439967db2c464c1ea494a86bff16c12971539081501f5c364364736f6c634300080f0033a26469706673582212208fe40d51d10dd94b4b88681095e99c8a793cd5a66e4a4aac4d78eb497edc644364736f6c634300080f0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.