ETH Price: $3,150.94 (+1.61%)

Contract

0xCA61945467371e534aFd26302D48D9A9E7dCb814
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x61018060177756332023-07-26 7:01:59481 days ago1690354919IN
 Contract Creation
0 ETH0.054130122.53111472

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

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

Contract Name:
CometWrapper

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 11 : CometWrapper.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {ERC4626} from "solmate/mixins/ERC4626.sol";
import {ERC20} from "solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {CometInterface, TotalsBasic} from "./vendor/CometInterface.sol";
import {CometHelpers} from "./CometHelpers.sol";
import {ICometRewards} from "./vendor/ICometRewards.sol";

/// @notice A vault contract that accepts deposits of a Comet token like cUSDCv3 as an asset
/// and mints shares which are the Wrapped Comet token.
contract CometWrapper is ERC4626, CometHelpers {
    using SafeTransferLib for ERC20;

    struct UserBasic {
        uint64 baseTrackingAccrued;
        uint64 baseTrackingIndex;
    }

    mapping(address => UserBasic) public userBasic;
    mapping(address => uint256) public rewardsClaimed;

    CometInterface public immutable comet;
    ICometRewards public immutable cometRewards;
    uint256 public immutable trackingIndexScale;
    uint256 internal immutable accrualDescaleFactor;

    constructor(ERC20 _asset, ICometRewards _cometRewards, string memory _name, string memory _symbol)
        ERC4626(_asset, _name, _symbol)
    {
        if (address(_cometRewards) == address(0)) revert ZeroAddress();
        // minimal validation that contract is CometRewards
        _cometRewards.rewardConfig(address(_asset));

        comet = CometInterface(address(_asset));
        cometRewards = _cometRewards;
        trackingIndexScale = comet.trackingIndexScale();
        accrualDescaleFactor = uint64(10 ** asset.decimals()) / BASE_ACCRUAL_SCALE;
    }

    /// @notice Returns total assets managed by the vault
    /// @return total assets
    function totalAssets() public view override returns (uint256) {
        uint64 baseSupplyIndex_ = accruedSupplyIndex();
        uint256 supply = totalSupply;
        return supply > 0 ? presentValueSupply(baseSupplyIndex_, supply) : 0;
    }

    /// @notice Deposits assets into the vault and gets shares (Wrapped Comet token) in return
    /// @param assets The amount of assets to be deposited by the caller
    /// @param receiver The recipient address of the minted shares
    /// @return shares The amount of shares that are minted to the receiver
    function deposit(uint256 assets, address receiver) public override returns (uint256 shares) {
        if (assets == 0) revert ZeroAssets();

        accrueInternal(receiver);
        int104 prevPrincipal = comet.userBasic(address(this)).principal;
        asset.safeTransferFrom(msg.sender, address(this), assets);
        shares = unsigned256(comet.userBasic(address(this)).principal - prevPrincipal);
        if (shares == 0) revert ZeroShares();
        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);
    }

    /// @notice Mints shares (Wrapped Comet) in exchange for Comet tokens
    /// @param shares The amount of shares to be minted for the receive
    /// @param receiver The recipient address of the minted shares
    /// @return assets The amount of assets that are deposited by the caller
    function mint(uint256 shares, address receiver) public override returns (uint256 assets) {
        if (shares == 0) revert ZeroShares();
        assets = convertToAssets(shares);
        if (assets == 0) revert ZeroAssets();

        accrueInternal(receiver);
        int104 prevPrincipal = comet.userBasic(address(this)).principal;
        asset.safeTransferFrom(msg.sender, address(this), assets);
        shares =  unsigned256(comet.userBasic(address(this)).principal - prevPrincipal);
        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);
    }

    /// @notice Withdraws assets (Comet) from the vault and burns corresponding shares (Wrapped Comet).
    /// Caller can only withdraw assets from owner if they have been given allowance to.
    /// @param assets The amount of assets to be withdrawn by the caller
    /// @param receiver The recipient address of the withdrawn assets
    /// @param owner The owner of the assets to be withdrawn
    /// @return shares The amount of shares of the owner that are burned
    function withdraw(uint256 assets, address receiver, address owner) public override returns (uint256 shares) {
        if (assets == 0) revert ZeroAssets();
        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender];

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        accrueInternal(owner);
        int104 prevPrincipal = comet.userBasic(address(this)).principal;
        asset.safeTransfer(receiver, assets);
        shares =  unsigned256(prevPrincipal - comet.userBasic(address(this)).principal);
        if (shares == 0) revert ZeroShares();
        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);
    }

    /// @notice Redeems shares (Wrapped Comet) in exchange for assets (Wrapped Comet).
    /// Caller can only withdraw assets from owner if they have been given allowance to.
    /// @param shares The amount of shares to be redeemed
    /// @param receiver The recipient address of the withdrawn assets
    /// @param owner The owner of the shares to be redeemed
    /// @return assets The amount of assets that is withdrawn and sent to the receiver
    function redeem(uint256 shares, address receiver, address owner) public override returns (uint256 assets) {
        if (shares == 0) revert ZeroShares();
        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }
        // Asset transfers in Comet may lead to decrease of this contract's principal/shares by 1 more than the 
        // `shares` argument. Taking into account this quirk in Comet's transfer logic, we always decrease `shares`
        // by 1 before converting to assets and doing the transfer. We then proceed to burn the actual `shares` amount
        // that was decreased during the Comet transfer. 
        // In this way, any rounding error would be in favor of CometWrapper and CometWrapper will be protected
        // from insolvency due to lack of assets that can be withdrawn by users.
        assets = convertToAssets(shares-1);
        if (assets == 0) revert ZeroAssets();

        accrueInternal(owner);
        int104 prevPrincipal = comet.userBasic(address(this)).principal;
        asset.safeTransfer(receiver, assets);
        shares =  unsigned256(prevPrincipal - comet.userBasic(address(this)).principal);
        if (shares == 0) revert ZeroShares();
        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);
    }

    /// @notice Transfer shares from caller to the recipient
    /// @param to The receiver of the shares (Wrapped Comet) to be transferred
    /// @param amount The amount of shares to be transferred
    /// @return bool Indicates success of the transfer
    function transfer(address to, uint256 amount) public override returns (bool) {
        transferInternal(msg.sender, to, amount);
        return true;
    }

    /// @notice Transfer shares from a specified source to a recipient
    /// @param from The source of the shares to be transferred
    /// @param to The receiver of the shares (Wrapped Comet) to be transferred
    /// @param amount The amount of shares to be transferred
    /// @return bool Indicates success of the transfer
    function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
        uint256 allowed = msg.sender == from ? type(uint256).max : allowance[from][msg.sender]; // Saves gas for limited approvals.

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

        transferInternal(from, to, amount);
        return true;
    }

    function transferInternal(address from, address to, uint256 amount) internal {
        // Accrue rewards before transferring assets
        comet.accrueAccount(address(this));
        updateTrackingIndex(from);
        updateTrackingIndex(to);

        balanceOf[from] -= amount;
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);
    }

    /// @notice Total assets of an account that are managed by this vault
    /// @dev The asset balance is computed from an account's shares balance which mirrors how Comet
    /// computes token balances. This is done this way since balances are ever-increasing due to 
    /// interest accrual.
    /// @param account The address to be queried
    /// @return The total amount of assets held by an account
    function underlyingBalance(address account) public view returns (uint256) {
        uint64 baseSupplyIndex_ = accruedSupplyIndex();
        uint256 principal = balanceOf[account];
        return principal > 0 ? presentValueSupply(baseSupplyIndex_, principal) : 0;
    }

    /// @dev Updates an account's `baseTrackingAccrued` which keeps track of rewards accrued by the account.
    /// This uses the latest `trackingSupplyIndex` from Comet to compute for rewards accrual for accounts
    /// that supply the base asset to Comet.
    function updateTrackingIndex(address account) internal {
        UserBasic memory basic = userBasic[account];
        uint256 principal = balanceOf[account];
        (, uint64 trackingSupplyIndex,) = getSupplyIndices();

        if (principal >= 0) {
            uint256 indexDelta = uint256(trackingSupplyIndex - basic.baseTrackingIndex);
            basic.baseTrackingAccrued +=
                safe64(principal * indexDelta / trackingIndexScale / accrualDescaleFactor);
        }
        basic.baseTrackingIndex = trackingSupplyIndex;
        userBasic[account] = basic;
    }

    function accrueInternal(address account) internal {
        comet.accrueAccount(address(this));
        updateTrackingIndex(account);
    }

    /// @notice Get the reward owed to an account
    /// @dev This is designed to exactly match computation of rewards in Comet
    /// and uses the same configuration as CometRewards. It is a combination of both
    /// [`getRewardOwed`](https://github.com/compound-finance/comet/blob/63e98e5d231ef50c755a9489eb346a561fc7663c/contracts/CometRewards.sol#L110) and [`getRewardAccrued`](https://github.com/compound-finance/comet/blob/63e98e5d231ef50c755a9489eb346a561fc7663c/contracts/CometRewards.sol#L171).
    /// @param account The address to be queried
    /// @return The total amount of rewards owed to an account
    function getRewardOwed(address account) external returns (uint256) {
        ICometRewards.RewardConfig memory config = cometRewards.rewardConfig(address(comet));
        return getRewardOwedInternal(config, account);
    }

    function getRewardOwedInternal(ICometRewards.RewardConfig memory config, address account) internal returns (uint256) {
        UserBasic memory basic = accrueRewards(account);
        uint256 claimed = rewardsClaimed[account];
        uint256 accrued = basic.baseTrackingAccrued;

        if (config.shouldUpscale) {
            accrued *= config.rescaleFactor;
        } else {
            accrued /= config.rescaleFactor;
        }

        uint256 owed = accrued > claimed ? accrued - claimed : 0;

        return owed;
    }

    /// @notice Claims caller's rewards and sends them to recipient
    /// @dev Always calls CometRewards for updated configs
    /// @param to The address that will receive the rewards
    function claimTo(address to) external {
        address from = msg.sender;
        ICometRewards.RewardConfig memory config = cometRewards.rewardConfig(address(comet));
        uint256 owed = getRewardOwedInternal(config, from);

        if (owed != 0) {
            rewardsClaimed[from] += owed;
            emit RewardClaimed(from, to, config.token, owed);
            cometRewards.claimTo(address(comet), address(this), address(this), true);
            ERC20(config.token).safeTransfer(to, owed);
        }
    }

    /// @notice Accrues rewards for the account
    /// @dev Latest trackingSupplyIndex is fetched from Comet so we can compute accurate rewards.
    /// This mirrors the logic for rewards accrual in CometRewards so we properly account for users'
    /// rewards as if they had used Comet directly.
    /// @param account The address to whose rewards we want to accrue
    /// @return The UserBasic struct with updated baseTrackingIndex and/or baseTrackingAccrued fields
    function accrueRewards(address account) public returns (UserBasic memory) {
        UserBasic memory basic = userBasic[account];
        uint256 principal = balanceOf[account];
        comet.accrueAccount(address(this));
        (, uint64 trackingSupplyIndex,) = getSupplyIndices();

        if (principal >= 0) {
            uint256 indexDelta = uint256(trackingSupplyIndex - basic.baseTrackingIndex);
            basic.baseTrackingAccrued +=
                safe64((principal * indexDelta) / trackingIndexScale / accrualDescaleFactor);
        }
        basic.baseTrackingIndex = trackingSupplyIndex;
        userBasic[account] = basic;

        return basic;
    }

    /// @dev This returns latest baseSupplyIndex regardless of whether comet.accrueAccount has been called for the
    /// current block. This works like `Comet.accruedInterestedIndices` at but not including computation of
    /// `baseBorrowIndex` since we do not need that index in CometWrapper:
    /// https://github.com/compound-finance/comet/blob/63e98e5d231ef50c755a9489eb346a561fc7663c/contracts/Comet.sol#L383-L394
    function accruedSupplyIndex() internal view returns (uint64) {
        (uint64 baseSupplyIndex_,,uint40 lastAccrualTime) = getSupplyIndices();
        uint256 timeElapsed = uint256(getNowInternal() - lastAccrualTime);
        if (timeElapsed > 0) {
            uint256 utilization = comet.getUtilization();
            uint256 supplyRate = comet.getSupplyRate(utilization);
            baseSupplyIndex_ += safe64(mulFactor(baseSupplyIndex_, supplyRate * timeElapsed));
        }
        return baseSupplyIndex_;
    }

    /// @dev To maintain accuracy, we fetch `baseSupplyIndex` and `trackingSupplyIndex` directly from Comet.
    /// baseSupplyIndex is used on the principal to get the user's latest balance including interest accruals.
    /// trackingSupplyIndex is used to compute for rewards accruals.
    function getSupplyIndices() internal view returns (uint64 baseSupplyIndex_, uint64 trackingSupplyIndex_, uint40 lastAccrualTime_) {
        TotalsBasic memory totals = comet.totalsBasic();
        baseSupplyIndex_ = totals.baseSupplyIndex;
        trackingSupplyIndex_ = totals.trackingSupplyIndex;
        lastAccrualTime_ = totals.lastAccrualTime;
    }

    /// @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
    /// scenario where all the conditions are met.
    /// @dev Treats shares as principal and computes for assets by taking into account interest accrual. Relies on latest
    /// `baseSupplyIndex` from Comet which is the global index used for interest accrual the from supply rate. 
    /// @param shares The amount of shares to be converted to assets
    /// @return The total amount of assets computed from the given shares
    function convertToAssets(uint256 shares) public view override returns (uint256) {
        uint64 baseSupplyIndex_ = accruedSupplyIndex();
        return shares > 0 ? presentValueSupply(baseSupplyIndex_, shares) : 0;
    }

    /// @notice Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
    /// scenario where all the conditions are met.
    /// @dev Assets are converted to shares by computing for the principal using the latest `baseSupplyIndex` from Comet.
    /// @param assets The amount of assets to be converted to shares
    /// @return The total amount of shares computed from the given assets
    function convertToShares(uint256 assets) public view override returns (uint256) {
        uint64 baseSupplyIndex_ = accruedSupplyIndex();
        return assets > 0 ? principalValueSupply(baseSupplyIndex_, assets) : 0;
    }

    /// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
    /// current on-chain conditions.
    /// @param shares The amount of shares to be converted to assets
    /// @return The total amount of assets required to mint the given shares
    function previewMint(uint256 shares) public view override returns (uint256) {
        return convertToAssets(shares);
    }

    /// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
    /// given current on-chain conditions.
    /// @param assets The amount of assets to be converted to shares
    /// @return The total amount of shares required to withdraw the given assets
    function previewWithdraw(uint256 assets) public view override returns (uint256) {
        return convertToShares(assets);
    }
}

File 2 of 11 : ERC4626.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

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

/// @notice Minimal ERC4626 tokenized Vault implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/mixins/ERC4626.sol)
abstract contract ERC4626 is ERC20 {
    using SafeTransferLib for ERC20;
    using FixedPointMathLib for uint256;

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

    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);

    event Withdraw(
        address indexed caller,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /*//////////////////////////////////////////////////////////////
                               IMMUTABLES
    //////////////////////////////////////////////////////////////*/

    ERC20 public immutable asset;

    constructor(
        ERC20 _asset,
        string memory _name,
        string memory _symbol
    ) ERC20(_name, _symbol, _asset.decimals()) {
        asset = _asset;
    }

    /*//////////////////////////////////////////////////////////////
                        DEPOSIT/WITHDRAWAL LOGIC
    //////////////////////////////////////////////////////////////*/

    function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) {
        // Check for rounding error since we round down in previewDeposit.
        require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }

    function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) {
        assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }

    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public virtual returns (uint256 shares) {
        shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up.

        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        beforeWithdraw(assets, shares);

        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        asset.safeTransfer(receiver, assets);
    }

    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) public virtual returns (uint256 assets) {
        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        // Check for rounding error since we round down in previewRedeem.
        require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS");

        beforeWithdraw(assets, shares);

        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        asset.safeTransfer(receiver, assets);
    }

    /*//////////////////////////////////////////////////////////////
                            ACCOUNTING LOGIC
    //////////////////////////////////////////////////////////////*/

    function totalAssets() public view virtual returns (uint256);

    function convertToShares(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
    }

    function convertToAssets(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);
    }

    function previewDeposit(uint256 assets) public view virtual returns (uint256) {
        return convertToShares(assets);
    }

    function previewMint(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);
    }

    function previewWithdraw(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());
    }

    function previewRedeem(uint256 shares) public view virtual returns (uint256) {
        return convertToAssets(shares);
    }

    /*//////////////////////////////////////////////////////////////
                     DEPOSIT/WITHDRAWAL LIMIT LOGIC
    //////////////////////////////////////////////////////////////*/

    function maxDeposit(address) public view virtual returns (uint256) {
        return type(uint256).max;
    }

    function maxMint(address) public view virtual returns (uint256) {
        return type(uint256).max;
    }

    function maxWithdraw(address owner) public view virtual returns (uint256) {
        return convertToAssets(balanceOf[owner]);
    }

    function maxRedeem(address owner) public view virtual returns (uint256) {
        return balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                          INTERNAL HOOKS LOGIC
    //////////////////////////////////////////////////////////////*/

    function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}

    function afterDeposit(uint256 assets, uint256 shares) internal virtual {}
}

File 3 of 11 : ERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

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

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

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

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

    string public name;

    string public symbol;

    uint8 public immutable decimals;

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

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

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

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

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

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

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

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

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

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

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

        return true;
    }

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

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

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

        return true;
    }

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

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

        balanceOf[from] -= amount;

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

        emit Transfer(from, to, amount);

        return true;
    }

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

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

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

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

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

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

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

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

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

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

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

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

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

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

File 4 of 11 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

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

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

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

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

        require(success, "ETH_TRANSFER_FAILED");
    }

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

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

        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

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

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because that's the total length of our calldata (4 + 32 * 3)
                // Counterintuitively, this call() must be positioned after the or() in the
                // surrounding and() because and() evaluates its arguments from right to left.
                call(gas(), token, 0, 0, 100, 0, 32)
            )

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, memPointer) // Restore the memPointer.
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

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

        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

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

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because that's the total length of our calldata (4 + 32 * 2)
                // Counterintuitively, this call() must be positioned after the or() in the
                // surrounding and() because and() evaluates its arguments from right to left.
                call(gas(), token, 0, 0, 68, 0, 32)
            )

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, memPointer) // Restore the memPointer.
        }

        require(success, "TRANSFER_FAILED");
    }

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

        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

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

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because that's the total length of our calldata (4 + 32 * 2)
                // Counterintuitively, this call() must be positioned after the or() in the
                // surrounding and() because and() evaluates its arguments from right to left.
                call(gas(), token, 0, 0, 68, 0, 32)
            )

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, memPointer) // Restore the memPointer.
        }

        require(success, "APPROVE_FAILED");
    }
}

File 5 of 11 : CometInterface.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

import "./CometMainInterface.sol";
import "./CometExtInterface.sol";

/**
 * @title Compound's Comet Interface
 * @notice An efficient monolithic money market protocol
 * @author Compound
 */
abstract contract CometInterface is CometMainInterface, CometExtInterface {
    struct UserBasic {
        int104 principal;
        uint64 baseTrackingIndex;
        uint64 baseTrackingAccrued;
        uint16 assetsIn;
        uint8 _reserved;
    }

    function userBasic(address account) external view virtual returns (UserBasic memory);

    struct TotalsCollateral {
        uint128 totalSupplyAsset;
        uint128 _reserved;
    }

    function totalsCollateral(address) external virtual returns (TotalsCollateral memory);
}

File 6 of 11 : CometHelpers.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {CometMath} from "./vendor/CometMath.sol";

/// @notice Includes helper functions ripped from different contracts in Comet instead
/// of copying whole contracts. Also includes error definitions, events, and constants.
contract CometHelpers is CometMath {
    uint64 internal constant FACTOR_SCALE = 1e18;
    uint64 internal constant BASE_INDEX_SCALE = 1e15;
    uint64 internal constant BASE_ACCRUAL_SCALE = 1e6;

    error LackAllowance();
    error ZeroShares();
    error ZeroAssets();
    error ZeroAddress();
    error TimestampTooLarge();

    event RewardClaimed(address indexed src, address indexed recipient, address indexed token, uint256 amount);

    /// @dev Multiply a number by a factor
    /// https://github.com/compound-finance/comet/blob/main/contracts/Comet.sol#L681-L683
    function mulFactor(uint256 n, uint256 factor) internal pure returns (uint256) {
        return n * factor / FACTOR_SCALE;
    }

    /// @dev The principal amount projected forward by the supply index
    /// From https://github.com/compound-finance/comet/blob/main/contracts/CometCore.sol#L83-L85
    function presentValueSupply(uint64 baseSupplyIndex_, uint256 principalValue_) internal pure returns (uint256) {
        return principalValue_ * baseSupplyIndex_ / BASE_INDEX_SCALE;
    }

    /// @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.
    /// From https://github.com/compound-finance/comet/blob/main/contracts/CometCore.sol#L109-L111
    function principalValueSupply(uint64 baseSupplyIndex_, uint256 presentValue_) internal pure returns (uint104) {
        return safe104((presentValue_ * BASE_INDEX_SCALE) / baseSupplyIndex_);
    }

    /// @dev The current timestamp
    /// From https://github.com/compound-finance/comet/blob/main/contracts/Comet.sol#L375-L378
    function getNowInternal() internal view virtual returns (uint40) {
        if (block.timestamp >= 2**40) revert TimestampTooLarge();
        return uint40(block.timestamp);
    }
}

File 7 of 11 : ICometRewards.sol
// SPDX-License-Identifier: ISC
pragma solidity 0.8.17;

interface ICometRewards {
    struct RewardConfig {
        address token;
        uint64 rescaleFactor;
        bool shouldUpscale;
    }

    struct RewardOwed {
        address token;
        uint256 owed;
    }

    function rewardConfig(address) external view returns (RewardConfig memory);

    function claim(address comet, address src, bool shouldAccrue) external;

    function getRewardOwed(address comet, address account) external returns (RewardOwed memory);

    function claimTo(address comet, address src, address to, bool shouldAccrue) external;
}

File 8 of 11 : FixedPointMathLib.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

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

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

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

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

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

    function powWad(int256 x, int256 y) internal pure returns (int256) {
        // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)
        return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0.
    }

    function expWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            // When the result is < 0.5 we return zero. This happens when
            // x <= floor(log(0.5e18) * 1e18) ~ -42e18
            if (x <= -42139678854452767551) return 0;

            // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
            // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
            if (x >= 135305999368893231589) revert("EXP_OVERFLOW");

            // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
            // for more intermediate precision and a binary basis. This base conversion
            // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
            x = (x << 78) / 5**18;

            // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
            // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
            // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
            int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
            x = x - k * 54916777467707473351141471128;

            // k is in the range [-61, 195].

            // Evaluate using a (6, 7)-term rational approximation.
            // p is made monic, we'll multiply by a scale factor later.
            int256 y = x + 1346386616545796478920950773328;
            y = ((y * x) >> 96) + 57155421227552351082224309758442;
            int256 p = y + x - 94201549194550492254356042504812;
            p = ((p * y) >> 96) + 28719021644029726153956944680412240;
            p = p * x + (4385272521454847904659076985693276 << 96);

            // We leave p in 2**192 basis so we don't need to scale it back up for the division.
            int256 q = x - 2855989394907223263936484059900;
            q = ((q * x) >> 96) + 50020603652535783019961831881945;
            q = ((q * x) >> 96) - 533845033583426703283633433725380;
            q = ((q * x) >> 96) + 3604857256930695427073651918091429;
            q = ((q * x) >> 96) - 14423608567350463180887372962807573;
            q = ((q * x) >> 96) + 26449188498355588339934803723976023;

            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial won't have zeros in the domain as all its roots are complex.
                // No scaling is necessary because p is already 2**96 too large.
                r := sdiv(p, q)
            }

            // r should be in the range (0.09, 0.25) * 2**96.

            // We now need to multiply r by:
            // * the scale factor s = ~6.031367120.
            // * the 2**k factor from the range reduction.
            // * the 1e18 / 2**96 factor for base conversion.
            // We do this all at once, with an intermediate result in 2**213
            // basis, so the final right shift is always by a positive amount.
            r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
        }
    }

    function lnWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            require(x > 0, "UNDEFINED");

            // We want to convert x from 10**18 fixed point to 2**96 fixed point.
            // We do this by multiplying by 2**96 / 10**18. But since
            // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
            // and add ln(2**96 / 10**18) at the end.

            // Reduce range of x to (1, 2) * 2**96
            // ln(2^k * x) = k * ln(2) + ln(x)
            int256 k = int256(log2(uint256(x))) - 96;
            x <<= uint256(159 - k);
            x = int256(uint256(x) >> 159);

            // Evaluate using a (8, 8)-term rational approximation.
            // p is made monic, we will multiply by a scale factor later.
            int256 p = x + 3273285459638523848632254066296;
            p = ((p * x) >> 96) + 24828157081833163892658089445524;
            p = ((p * x) >> 96) + 43456485725739037958740375743393;
            p = ((p * x) >> 96) - 11111509109440967052023855526967;
            p = ((p * x) >> 96) - 45023709667254063763336534515857;
            p = ((p * x) >> 96) - 14706773417378608786704636184526;
            p = p * x - (795164235651350426258249787498 << 96);

            // We leave p in 2**192 basis so we don't need to scale it back up for the division.
            // q is monic by convention.
            int256 q = x + 5573035233440673466300451813936;
            q = ((q * x) >> 96) + 71694874799317883764090561454958;
            q = ((q * x) >> 96) + 283447036172924575727196451306956;
            q = ((q * x) >> 96) + 401686690394027663651624208769553;
            q = ((q * x) >> 96) + 204048457590392012362485061816622;
            q = ((q * x) >> 96) + 31853899698501571402653359427138;
            q = ((q * x) >> 96) + 909429971244387300277376558375;
            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial is known not to have zeros in the domain.
                // No scaling required because p is already 2**96 too large.
                r := sdiv(p, q)
            }

            // r is in the range (0, 0.125) * 2**96

            // Finalization, we need to:
            // * multiply by the scale factor s = 5.549…
            // * add ln(2**96 / 10**18)
            // * add k * ln(2)
            // * multiply by 10**18 / 2**96 = 5**18 >> 78

            // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
            r *= 1677202110996718588342820967067443963516166;
            // add ln(2) * k * 5e18 * 2**192
            r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
            // add ln(2**96 / 10**18) * 5e18 * 2**192
            r += 600920179829731861736702779321621459595472258049074101567377883020018308;
            // base conversion: mul 2**18 / 2**192
            r >>= 174;
        }
    }

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

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // First, divide z - 1 by the denominator and add 1.
            // We allow z - 1 to underflow if z is 0, because we multiply the
            // end result by 0 if z is zero, ensuring we return 0 if z is zero.
            z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
        }
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    function log2(uint256 x) internal pure returns (uint256 r) {
        require(x > 0, "UNDEFINED");

        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            r := or(r, shl(2, lt(0xf, shr(r, x))))
            r := or(r, shl(1, lt(0x3, shr(r, x))))
            r := or(r, lt(0x1, shr(r, x)))
        }
    }

    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // z will equal 0 if y is 0, unlike in Solidity where it will revert.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // z will equal 0 if y is 0, unlike in Solidity where it will revert.
            z := div(x, y)
        }
    }

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

File 9 of 11 : CometMainInterface.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

struct AssetInfo {
    uint8 offset;
    address asset;
    address priceFeed;
    uint64 scale;
    uint64 borrowCollateralFactor;
    uint64 liquidateCollateralFactor;
    uint64 liquidationFactor;
    uint128 supplyCap;
}

/**
 * @title Compound's Comet Main Interface (without Ext)
 * @notice An efficient monolithic money market protocol
 * @author Compound
 */
abstract contract CometMainInterface {
    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 SupplyCapExceeded();
    error TimestampTooLarge();
    error TooManyAssets();
    error TooMuchSlippage();
    error TransferInFailed();
    error TransferOutFailed();
    error Unauthorized();

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

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

    /// @notice Event emitted when a borrow position is absorbed by the protocol
    event AbsorbDebt(address indexed absorber, address indexed borrower, uint256 basePaidOut, uint256 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,
        uint256 collateralAbsorbed,
        uint256 usdValue
    );

    /// @notice Event emitted when a collateral asset is purchased from the protocol
    event BuyCollateral(address indexed buyer, address indexed asset, uint256 baseAmount, uint256 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, uint256 amount);

    function supply(address asset, uint256 amount) external virtual;

    function supplyTo(address dst, address asset, uint256 amount) external virtual;

    function supplyFrom(address from, address dst, address asset, uint256 amount) external virtual;

    function transfer(address dst, uint256 amount) external virtual returns (bool);

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

    function transferAsset(address dst, address asset, uint256 amount) external virtual;

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

    function withdraw(address asset, uint256 amount) external virtual;

    function withdrawTo(address to, address asset, uint256 amount) external virtual;

    function withdrawFrom(address src, address to, address asset, uint256 amount) external virtual;

    function approveThis(address manager, address asset, uint256 amount) external virtual;

    function withdrawReserves(address to, uint256 amount) external virtual;

    function absorb(address absorber, address[] calldata accounts) external virtual;

    function buyCollateral(address asset, uint256 minAmount, uint256 baseAmount, address recipient) external virtual;

    function quoteCollateral(address asset, uint256 baseAmount) public view virtual returns (uint256);

    function getAssetInfo(uint8 i) public view virtual returns (AssetInfo memory);

    function getAssetInfoByAddress(address asset) public view virtual returns (AssetInfo memory);

    function getReserves() public view virtual returns (int256);

    function getPrice(address priceFeed) public view virtual returns (uint256);

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

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

    function totalSupply() external view virtual returns (uint256);

    function totalBorrow() external view virtual returns (uint256);

    function balanceOf(address owner) public view virtual returns (uint256);

    function borrowBalanceOf(address account) public view virtual returns (uint256);

    function pause(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused)
        external
        virtual;

    function isSupplyPaused() public view virtual returns (bool);

    function isTransferPaused() public view virtual returns (bool);

    function isWithdrawPaused() public view virtual returns (bool);

    function isAbsorbPaused() public view virtual returns (bool);

    function isBuyPaused() public view virtual returns (bool);

    function accrueAccount(address account) external virtual;

    function getSupplyRate(uint256 utilization) public view virtual returns (uint64);

    function getBorrowRate(uint256 utilization) public view virtual returns (uint64);

    function getUtilization() public view virtual returns (uint256);

    function governor() external view virtual returns (address);

    function pauseGuardian() external view virtual returns (address);

    function baseToken() external view virtual returns (address);

    function baseTokenPriceFeed() external view virtual returns (address);

    function extensionDelegate() external view virtual returns (address);

    /// @dev uint64
    function supplyKink() external view virtual returns (uint256);

    /// @dev uint64
    function supplyPerSecondInterestRateSlopeLow() external view virtual returns (uint256);

    /// @dev uint64
    function supplyPerSecondInterestRateSlopeHigh() external view virtual returns (uint256);

    /// @dev uint64
    function supplyPerSecondInterestRateBase() external view virtual returns (uint256);

    /// @dev uint64
    function borrowKink() external view virtual returns (uint256);

    /// @dev uint64
    function borrowPerSecondInterestRateSlopeLow() external view virtual returns (uint256);

    /// @dev uint64
    function borrowPerSecondInterestRateSlopeHigh() external view virtual returns (uint256);

    /// @dev uint64
    function borrowPerSecondInterestRateBase() external view virtual returns (uint256);

    /// @dev uint64
    function storeFrontPriceFactor() external view virtual returns (uint256);

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

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

    /// @dev uint64
    function baseTrackingSupplySpeed() external view virtual returns (uint256);

    /// @dev uint64
    function baseTrackingBorrowSpeed() external view virtual returns (uint256);

    /// @dev uint104
    function baseMinForRewards() external view virtual returns (uint256);

    /// @dev uint104
    function baseBorrowMin() external view virtual returns (uint256);

    /// @dev uint104
    function targetReserves() external view virtual returns (uint256);

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

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

    function initializeStorage() external virtual;
}

File 10 of 11 : CometExtInterface.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

struct TotalsBasic {
    uint64 baseSupplyIndex;
    uint64 baseBorrowIndex;
    uint64 trackingSupplyIndex;
    uint64 trackingBorrowIndex;
    uint104 totalSupplyBase;
    uint104 totalBorrowBase;
    uint40 lastAccrualTime;
    uint8 pauseFlags;
}

/**
 * @title Compound's Comet Ext Interface
 * @notice An efficient monolithic money market protocol
 * @author Compound
 */
abstract contract CometExtInterface {
    error BadAmount();
    error BadNonce();
    error BadSignatory();
    error InvalidValueS();
    error InvalidValueV();
    error SignatureExpired();

    function allow(address manager, bool isAllowed) external virtual;

    function allowBySig(
        address owner,
        address manager,
        bool isAllowed,
        uint256 nonce,
        uint256 expiry,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external virtual;

    function collateralBalanceOf(address account, address asset) external view virtual returns (uint128);

    function baseTrackingAccrued(address account) external view virtual returns (uint64);

    function baseAccrualScale() external view virtual returns (uint64);

    function baseIndexScale() external view virtual returns (uint64);

    function factorScale() external view virtual returns (uint64);

    function priceScale() external view virtual returns (uint64);

    function maxAssets() external view virtual returns (uint8);

    function totalsBasic() external view virtual returns (TotalsBasic memory);

    function version() external view virtual returns (string memory);

    /**
     * ===== ERC20 interfaces =====
     * Does not include the following functions/events, which are defined in `CometMainInterface` instead:
     * - function decimals() virtual external view returns (uint8)
     * - function totalSupply() virtual external view returns (uint256)
     * - function transfer(address dst, uint amount) virtual external returns (bool)
     * - function transferFrom(address src, address dst, uint amount) virtual external returns (bool)
     * - function balanceOf(address owner) virtual external view returns (uint256)
     * - event Transfer(address indexed from, address indexed to, uint256 amount)
     */
    function name() external view virtual returns (string memory);

    function symbol() external view virtual returns (string memory);

    /**
     * @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)
     * @return Whether or not the approval succeeded
     */
    function approve(address spender, uint256 amount) external virtual returns (bool);

    /**
     * @notice Get the current allowance from `owner` for `spender`
     * @param owner The address of the account which owns the tokens to be spent
     * @param spender The address of the account which may transfer tokens
     * @return The number of tokens allowed to be spent (-1 means infinite)
     */
    function allowance(address owner, address spender) external view virtual returns (uint256);

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

File 11 of 11 : CometMath.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

/**
 * @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(uint256 n) internal pure returns (uint64) {
        if (n > type(uint64).max) revert InvalidUInt64();
        return uint64(n);
    }

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

    function safe128(uint256 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;
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ERC20","name":"_asset","type":"address"},{"internalType":"contract ICometRewards","name":"_cometRewards","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidInt104","type":"error"},{"inputs":[],"name":"InvalidInt256","type":"error"},{"inputs":[],"name":"InvalidUInt104","type":"error"},{"inputs":[],"name":"InvalidUInt128","type":"error"},{"inputs":[],"name":"InvalidUInt64","type":"error"},{"inputs":[],"name":"LackAllowance","type":"error"},{"inputs":[],"name":"NegativeNumber","type":"error"},{"inputs":[],"name":"TimestampTooLarge","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAssets","type":"error"},{"inputs":[],"name":"ZeroShares","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accrueRewards","outputs":[{"components":[{"internalType":"uint64","name":"baseTrackingAccrued","type":"uint64"},{"internalType":"uint64","name":"baseTrackingIndex","type":"uint64"}],"internalType":"struct CometWrapper.UserBasic","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"claimTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"comet","outputs":[{"internalType":"contract CometInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cometRewards","outputs":[{"internalType":"contract ICometRewards","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getRewardOwed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardsClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trackingIndexScale","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"underlyingBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userBasic","outputs":[{"internalType":"uint64","name":"baseTrackingAccrued","type":"uint64"},{"internalType":"uint64","name":"baseTrackingIndex","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102275760003560e01c80637ecebe0011610130578063ba3e9c12116100b8578063d505accf1161007c578063d505accf14610540578063d905777e14610553578063dc4abafd1461057c578063dd62ed3e146105d0578063ef8b30f71461029257600080fd5b8063ba3e9c12146104d3578063c63d75b6146103c8578063c6e6f592146104fa578063ce96cb771461050d578063d3f730fd1461052057600080fd5b8063a9059cbb116100ff578063a9059cbb14610473578063aba7f15e14610486578063b3d7f6b9146103dd578063b460af94146104ad578063ba087652146104c057600080fd5b80637ecebe001461042357806394bf804d1461044357806395d89b4114610456578063a262f5f81461045e57600080fd5b806332315972116101b35780633e642575116101825780633e642575146103b5578063402d267d146103c85780634cdad506146103dd5780636e553f65146103f057806370a082311461040357600080fd5b8063323159721461030d5780633644e5151461034c57806338d52e0f146103545780633d39955c1461037b57600080fd5b80630a28a477116101fa5780630a28a4771461029257806318160ddd146102a557806323b872dd146102ae5780632a846398146102c1578063313ce567146102d457600080fd5b806301e1d1141461022c57806306fdde031461024757806307a2d13a1461025c578063095ea7b31461026f575b600080fd5b6102346105fb565b6040519081526020015b60405180910390f35b61024f610629565b60405161023e91906121f4565b61023461026a366004612242565b6106b7565b61028261027d366004612270565b6106e4565b604051901515815260200161023e565b6102346102a0366004612242565b610751565b61023460025481565b6102826102bc36600461229c565b61075c565b6102346102cf3660046122dd565b61080d565b6102fb7f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff909116815260200161023e565b6103347f0000000000000000000000001b0e765f6224c21223aea2af16c1c46e38885a4081565b6040516001600160a01b03909116815260200161023e565b6102346108c8565b6103347f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae9481565b61038e6103893660046122dd565b610923565b6040805182516001600160401b03908116825260209384015116928101929092520161023e565b6102346103c33660046122dd565b610afd565b6102346103d63660046122dd565b5060001990565b6102346103eb366004612242565b610b42565b6102346103fe3660046122fa565b610b4d565b6102346104113660046122dd565b60036020526000908152604090205481565b6102346104313660046122dd565b60056020526000908152604090205481565b6102346104513660046122fa565b610d59565b61024f610f15565b61047161046c3660046122dd565b610f22565b005b610282610481366004612270565b61113d565b6102347f00000000000000000000000000000000000000000000000000038d7ea4c6800081565b6102346104bb36600461232a565b611153565b6102346104ce36600461232a565b6113c8565b6103347f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae9481565b610234610508366004612242565b61161a565b61023461051b3660046122dd565b611650565b61023461052e3660046122dd565b60076020526000908152604090205481565b61047161054e36600461237b565b611672565b6102346105613660046122dd565b6001600160a01b031660009081526003602052604090205490565b6105b061058a3660046122dd565b6006602052600090815260409020546001600160401b0380821691600160401b90041682565b604080516001600160401b0393841681529290911660208301520161023e565b6102346105de3660046123ec565b600460209081526000928352604080842090915290825290205481565b6000806106066118bb565b60025490915080610618576000610622565b6106228282611a47565b9250505090565b600080546106369061241a565b80601f01602080910402602001604051908101604052809291908181526020018280546106629061241a565b80156106af5780601f10610684576101008083540402835291602001916106af565b820191906000526020600020905b81548152906001019060200180831161069257829003601f168201915b505050505081565b6000806106c26118bb565b9050600083116106d35760006106dd565b6106dd8184611a47565b9392505050565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061073f9086815260200190565b60405180910390a35060015b92915050565b600061074b8261161a565b600080336001600160a01b03861614610798576001600160a01b038516600090815260046020908152604080832033845290915290205461079c565b6000195b9050828110156107bf57604051635234951560e11b815260040160405180910390fd5b60001981146107f7576107d2838261246a565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b610802858585611a6e565b506001949350505050565b60405163045136d760e31b81526001600160a01b037f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae948116600483015260009182917f0000000000000000000000001b0e765f6224c21223aea2af16c1c46e38885a401690632289b6b890602401606060405180830381865afa158015610898573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bc91906124d0565b90506106dd8184611b89565b60007f000000000000000000000000000000000000000000000000000000000000000146146108fe576108f9611c2a565b905090565b507fe5647133ed7adae9d78fdebe116352a8602b0ea00393792297a8c19951a7b7de90565b604080518082018252600080825260208083018290526001600160a01b03858116808452600683528584208651808801885290546001600160401b038082168352600160401b909104168185015290845260039092529184902054935163bfe69c8d60e01b81523060048201529293909290917f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae94169063bfe69c8d90602401600060405180830381600087803b1580156109dc57600080fd5b505af11580156109f0573d6000803e3d6000fd5b5050505060006109fe611cc4565b509150506000836020015182610a149190612552565b6001600160401b03169050610a877f000000000000000000000000000000000000000000000000000000e8d4a510007f00000000000000000000000000000000000000000000000000038d7ea4c68000610a6e8487612579565b610a789190612590565b610a829190612590565b611d66565b84518590610a969083906125b2565b6001600160401b0316905250506001600160401b0390811660208085019182526001600160a01b039096166000908152600690965260409095208351815496518316600160401b026001600160801b03199097169216919091179490941790935592915050565b600080610b086118bb565b6001600160a01b03841660009081526003602052604090205490915080610b30576000610b3a565b610b3a8282611a47565b949350505050565b600061074b826106b7565b600082600003610b7057604051630cb65c7760e21b815260040160405180910390fd5b610b7982611d94565b60405163dc4abafd60e01b81523060048201526000907f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b03169063dc4abafd9060240160a060405180830381865afa158015610be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0491906125dd565b519050610c3c6001600160a01b037f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae9416333087611e19565b60405163dc4abafd60e01b8152306004820152610cde9082906001600160a01b037f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae94169063dc4abafd906024015b60a060405180830381865afa158015610ca7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ccb91906125dd565b51610cd6919061268c565b600c0b611ea7565b915081600003610d0157604051639811e0c760e01b815260040160405180910390fd5b610d0b8383611eca565b60408051858152602081018490526001600160a01b0385169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d791015b60405180910390a35092915050565b600082600003610d7c57604051639811e0c760e01b815260040160405180910390fd5b610d85836106b7565b905080600003610da857604051630cb65c7760e21b815260040160405180910390fd5b610db182611d94565b60405163dc4abafd60e01b81523060048201526000907f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b03169063dc4abafd9060240160a060405180830381865afa158015610e18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3c91906125dd565b519050610e746001600160a01b037f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae9416333085611e19565b60405163dc4abafd60e01b8152306004820152610ec69082906001600160a01b037f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae94169063dc4abafd90602401610c8a565b9350610ed28385611eca565b60408051838152602081018690526001600160a01b0385169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79101610d4a565b600180546106369061241a565b60405163045136d760e31b81526001600160a01b037f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae948116600483015233916000917f0000000000000000000000001b0e765f6224c21223aea2af16c1c46e38885a401690632289b6b890602401606060405180830381865afa158015610fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd191906124d0565b90506000610fdf8284611b89565b90508015611137576001600160a01b0383166000908152600760205260408120805483929061100f9084906126c5565b9250508190555081600001516001600160a01b0316846001600160a01b0316846001600160a01b03167f2422cac5e23c46c890fdcf42d0c64757409df6832174df639337558f09d99c688460405161106991815260200190565b60405180910390a46040516313fe176560e21b81526001600160a01b037f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae948116600483015230602483018190526044830152600160648301527f0000000000000000000000001b0e765f6224c21223aea2af16c1c46e38885a401690634ff85d9490608401600060405180830381600087803b15801561110857600080fd5b505af115801561111c573d6000803e3d6000fd5b5050835161113792506001600160a01b031690508583611f36565b50505050565b600061114a338484611a6e565b50600192915050565b60008360000361117657604051630cb65c7760e21b815260040160405180910390fd5b336001600160a01b038316146111e4576001600160a01b038216600090815260046020908152604080832033845290915290205460001981146111e2576111bd828261246a565b6001600160a01b03841660009081526004602090815260408083203384529091529020555b505b6111ed82611d94565b60405163dc4abafd60e01b81523060048201526000907f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b03169063dc4abafd9060240160a060405180830381865afa158015611254573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127891906125dd565b5190506112af6001600160a01b037f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae94168587611f36565b60405163dc4abafd60e01b8152306004820152611347907f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b03169063dc4abafd906024015b60a060405180830381865afa158015611318573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133c91906125dd565b51610cd6908361268c565b91508160000361136a57604051639811e0c760e01b815260040160405180910390fd5b6113748383611fb4565b60408051868152602081018490526001600160a01b03808616929087169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db91015b60405180910390a4509392505050565b6000836000036113eb57604051639811e0c760e01b815260040160405180910390fd5b336001600160a01b03831614611459576001600160a01b0382166000908152600460209081526040808320338452909152902054600019811461145757611432858261246a565b6001600160a01b03841660009081526004602090815260408083203384529091529020555b505b61146761026a60018661246a565b90508060000361148a57604051630cb65c7760e21b815260040160405180910390fd5b61149382611d94565b60405163dc4abafd60e01b81523060048201526000907f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b03169063dc4abafd9060240160a060405180830381865afa1580156114fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151e91906125dd565b5190506115556001600160a01b037f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae94168584611f36565b60405163dc4abafd60e01b81523060048201526115a5907f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b03169063dc4abafd906024016112fb565b9450846000036115c857604051639811e0c760e01b815260040160405180910390fd5b6115d28386611fb4565b60408051838152602081018790526001600160a01b03808616929087169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db91016113b8565b6000806116256118bb565b905060008311611636576000611640565b6116408184612028565b6001600160681b03169392505050565b6001600160a01b03811660009081526003602052604081205461074b906106b7565b428410156116c75760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b600060016116d36108c8565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156117df573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906118155750876001600160a01b0316816001600160a01b0316145b6118525760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b60448201526064016116be565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60008060006118c8611cc4565b92505091506000816118d8612057565b6118e291906126d8565b64ffffffffff1690508015611a3f5760007f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b0316637eb711316040518163ffffffff1660e01b8152600401602060405180830381865afa158015611951573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197591906126f6565b60405163d955759d60e01b8152600481018290529091506000906001600160a01b037f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae94169063d955759d90602401602060405180830381865afa1580156119e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a04919061270f565b6001600160401b03169050611a30610a82866001600160401b03168584611a2b9190612579565b612084565b611a3a90866125b2565b945050505b509092915050565b600066038d7ea4c68000611a646001600160401b03851684612579565b6106dd9190612590565b60405163bfe69c8d60e01b81523060048201527f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b03169063bfe69c8d90602401600060405180830381600087803b158015611acf57600080fd5b505af1158015611ae3573d6000803e3d6000fd5b50505050611af083612099565b611af982612099565b6001600160a01b03831660009081526003602052604081208054839290611b2190849061246a565b90915550506001600160a01b03808316600081815260036020526040908190208054850190555190918516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611b7c9085815260200190565b60405180910390a3505050565b600080611b9583610923565b6001600160a01b0384166000908152600760205260409081902054825191870151929350916001600160401b039091169015611bea576020860151611be3906001600160401b031682612579565b9050611c05565b6020860151611c02906001600160401b031682612590565b90505b6000828211611c15576000611c1f565b611c1f838361246a565b979650505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051611c5c919061272a565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6000806000807f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b031663b9f0baf76040518163ffffffff1660e01b815260040161010060405180830381865afa158015611d29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4d91906127e0565b8051604082015160c09092015190969195509350915050565b60006001600160401b03821115611d90576040516372a1cb5160e11b815260040160405180910390fd5b5090565b60405163bfe69c8d60e01b81523060048201527f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b03169063bfe69c8d90602401600060405180830381600087803b158015611df557600080fd5b505af1158015611e09573d6000803e3d6000fd5b50505050611e1681612099565b50565b60006040516323b872dd60e01b6000528460045283602452826044526020600060646000808a5af13d15601f3d1160016000511416171691506000606052806040525080611ea05760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016116be565b5050505050565b600080821215611d905760405163363b64b760e11b815260040160405180910390fd5b8060026000828254611edc91906126c5565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91015b60405180910390a35050565b600060405163a9059cbb60e01b6000528360045282602452602060006044600080895af13d15601f3d11600160005114161716915060006060528060405250806111375760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016116be565b6001600160a01b03821660009081526003602052604081208054839290611fdc90849061246a565b90915550506002805482900390556040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001611f2a565b60006106dd6001600160401b03841661204866038d7ea4c6800085612579565b6120529190612590565b6121ca565b600065010000000000421061207f57604051633d32ffdb60e01b815260040160405180910390fd5b504290565b6000670de0b6b3a7640000611a648385612579565b6001600160a01b03811660008181526006602090815260408083208151808301835290546001600160401b038082168352600160401b90910416818401529383526003909152812054906120eb611cc4565b5091505060008360200151826121019190612552565b6001600160401b0316905061215b7f000000000000000000000000000000000000000000000000000000e8d4a510007f00000000000000000000000000000000000000000000000000038d7ea4c68000610a6e8487612579565b8451859061216a9083906125b2565b6001600160401b0316905250506001600160401b0390811660208085019182526001600160a01b039095166000908152600690955260409094209251835494518216600160401b026001600160801b031990951691161792909217905550565b60006001600160681b03821115611d9057604051630dc7925560e11b815260040160405180910390fd5b600060208083528351808285015260005b8181101561222157858101830151858201604001528201612205565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561225457600080fd5b5035919050565b6001600160a01b0381168114611e1657600080fd5b6000806040838503121561228357600080fd5b823561228e8161225b565b946020939093013593505050565b6000806000606084860312156122b157600080fd5b83356122bc8161225b565b925060208401356122cc8161225b565b929592945050506040919091013590565b6000602082840312156122ef57600080fd5b81356106dd8161225b565b6000806040838503121561230d57600080fd5b82359150602083013561231f8161225b565b809150509250929050565b60008060006060848603121561233f57600080fd5b8335925060208401356123518161225b565b915060408401356123618161225b565b809150509250925092565b60ff81168114611e1657600080fd5b600080600080600080600060e0888a03121561239657600080fd5b87356123a18161225b565b965060208801356123b18161225b565b9550604088013594506060880135935060808801356123cf8161236c565b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156123ff57600080fd5b823561240a8161225b565b9150602083013561231f8161225b565b600181811c9082168061242e57607f821691505b60208210810361244e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561074b5761074b612454565b60405161010081016001600160401b03811182821017156124ae57634e487b7160e01b600052604160045260246000fd5b60405290565b80516001600160401b03811681146124cb57600080fd5b919050565b6000606082840312156124e257600080fd5b604051606081018181106001600160401b038211171561251257634e487b7160e01b600052604160045260246000fd5b60405282516125208161225b565b815261252e602084016124b4565b60208201526040830151801515811461254657600080fd5b60408201529392505050565b6001600160401b0382811682821603908082111561257257612572612454565b5092915050565b808202811582820484141761074b5761074b612454565b6000826125ad57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160401b0381811683821601908082111561257257612572612454565b80516124cb8161236c565b600060a082840312156125ef57600080fd5b60405160a081018181106001600160401b038211171561261f57634e487b7160e01b600052604160045260246000fd5b6040528251600c81900b811461263457600080fd5b8152612642602084016124b4565b6020820152612653604084016124b4565b6040820152606083015161ffff8116811461266d57600080fd5b606082015260808301516126808161236c565b60808201529392505050565b600c82810b9082900b036c7fffffffffffffffffffffffff1981126c7fffffffffffffffffffffffff8213171561074b5761074b612454565b8082018082111561074b5761074b612454565b64ffffffffff82811682821603908082111561257257612572612454565b60006020828403121561270857600080fd5b5051919050565b60006020828403121561272157600080fd5b6106dd826124b4565b600080835481600182811c91508083168061274657607f831692505b6020808410820361276557634e487b7160e01b86526022600452602486fd5b818015612779576001811461278e576127bb565b60ff19861689528415158502890196506127bb565b60008a81526020902060005b868110156127b35781548b82015290850190830161279a565b505084890196505b509498975050505050505050565b80516001600160681b03811681146124cb57600080fd5b600061010082840312156127f357600080fd5b6127fb61247d565b612804836124b4565b8152612812602084016124b4565b6020820152612823604084016124b4565b6040820152612834606084016124b4565b6060820152612845608084016127c9565b608082015261285660a084016127c9565b60a082015260c083015164ffffffffff8116811461287357600080fd5b60c082015261288460e084016125d2565b60e0820152939250505056fea2646970667358221220cc6c03f1a5fa6a87a40f1b7d010a50f34794cdb1765384556dad0622e3e0300564736f6c63430008110033

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.