ETH Price: $2,064.98 (-1.17%)
Gas: 0.06 GWei
 

Overview

ETH Balance

Scroll LogoScroll LogoScroll Logo0 ETH

ETH Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw142242042025-03-25 14:25:134 hrs ago1742912713IN
0x63FdAFA5...1291ec50f
0 ETH0.000005040.04794632
Withdraw141063172025-03-19 4:30:156 days ago1742358615IN
0x63FdAFA5...1291ec50f
0 ETH0.000005180.05
Withdraw140263272025-03-14 14:07:0311 days ago1741961223IN
0x63FdAFA5...1291ec50f
0 ETH0.000008020.05976287
Withdraw140243012025-03-14 11:45:5511 days ago1741952755IN
0x63FdAFA5...1291ec50f
0 ETH0.000005340.04966816
Withdraw140227282025-03-14 9:43:5411 days ago1741945434IN
0x63FdAFA5...1291ec50f
0 ETH0.000005080.0467484
Withdraw140166622025-03-14 0:49:5311 days ago1741913393IN
0x63FdAFA5...1291ec50f
0 ETH0.000004260.03995763
Withdraw140147352025-03-13 21:55:5911 days ago1741902959IN
0x63FdAFA5...1291ec50f
0 ETH0.000004270.03931745
Withdraw140084732025-03-13 14:36:4212 days ago1741876602IN
0x63FdAFA5...1291ec50f
0 ETH0.000005920.03995155
Remove_collatera...140079062025-03-13 13:59:4412 days ago1741874384IN
0x63FdAFA5...1291ec50f
0 ETH0.000005320.05
Withdraw140074732025-03-13 13:32:5312 days ago1741872773IN
0x63FdAFA5...1291ec50f
0 ETH0.000006780.05
Withdraw140048732025-03-13 10:42:1312 days ago1741862533IN
0x63FdAFA5...1291ec50f
0 ETH0.000005720.04571155
Withdraw139994172025-03-13 4:12:3612 days ago1741839156IN
0x63FdAFA5...1291ec50f
0 ETH0.000005140.0402331
Withdraw139936612025-03-12 19:49:0312 days ago1741808943IN
0x63FdAFA5...1291ec50f
0 ETH0.000005010.03929943
Withdraw139911372025-03-12 16:31:1613 days ago1741797076IN
0x63FdAFA5...1291ec50f
0 ETH0.00000690.04935316
Withdraw139897192025-03-12 14:51:5313 days ago1741791113IN
0x63FdAFA5...1291ec50f
0 ETH0.000006190.04253936
Withdraw139814832025-03-12 5:52:1613 days ago1741758736IN
0x63FdAFA5...1291ec50f
0 ETH0.000004940.03930349
Withdraw139805232025-03-12 4:29:0613 days ago1741753746IN
0x63FdAFA5...1291ec50f
0 ETH0.000006630.05
Withdraw139784792025-03-12 1:48:1613 days ago1741744096IN
0x63FdAFA5...1291ec50f
0 ETH0.000004930.03930933
Withdraw139658762025-03-11 10:27:5314 days ago1741688873IN
0x63FdAFA5...1291ec50f
0 ETH0.000006020.04673729
Remove_collatera...139598712025-03-11 3:29:1714 days ago1741663757IN
0x63FdAFA5...1291ec50f
0 ETH0.000004710.03934622
Withdraw139551522025-03-10 22:25:3614 days ago1741645536IN
0x63FdAFA5...1291ec50f
0 ETH0.000004750.04042308
Withdraw139548342025-03-10 22:00:4014 days ago1741644040IN
0x63FdAFA5...1291ec50f
0 ETH0.000005740.05
Remove_collatera...139532502025-03-10 20:20:0514 days ago1741638005IN
0x63FdAFA5...1291ec50f
0 ETH0.000010670.07
Repay139532422025-03-10 20:19:3314 days ago1741637973IN
0x63FdAFA5...1291ec50f
0 ETH0.000010510.07
Withdraw139508612025-03-10 18:23:5215 days ago1741631032IN
0x63FdAFA5...1291ec50f
0 ETH0.000016230.04296538
View all transactions

Latest 1 internal transaction

Parent Transaction Hash Block From To
31473882024-02-07 23:12:20411 days ago1707347540  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CogPair

Compiler Version
vyper:0.3.10

Optimization Enabled:
N/A

Other Settings:
default evmVersion, GNU AGPLv3 license

Contract Source Code (Vyper language format)

# @version 0.3.10

"""
@title CogPair
@author cog.finance
@license GNU Affero General Public License v3.0
@notice Implementation of an isolated lending pool with PoL in Vyper
@dev ERC20 support for True/revert, return True/False, return None, ty Curve for the inspiration
"""

from vyper.interfaces import ERC20
from vyper.interfaces import ERC20Detailed

# ///////////////////////////////////////////////////// #
#                  Rebase Math Helpers                  #
# ///////////////////////////////////////////////////// #

struct Rebase:
        elastic: uint128
        base: uint128


@pure
@internal
def to_base_round_up(total: Rebase, elastic: uint256) -> uint256:
    """
    @param total - The Rebase value which should be used to derive the relative base value
    @param elastic - The elastic value to convert to a relative base value
    @param round_up - Self explanatory
    """
    if total.elastic == 0:
        # If elastic is 0, then 0/n = 0 ∀ n ∈ R
        return elastic
    else:
        # Base is equal to elastic * (total.base / total.elastic), essentially a ratio
        base: uint256 = (elastic * convert(total.base, uint256)) / convert(
            total.elastic, uint256
        )

        # mamushi: Exhibit 1
        if (
            (base * convert(total.elastic, uint256))
            / convert(total.base, uint256)
        ) < elastic:
            base = base + 1

        return base


@pure
@internal
def to_elastic(total: Rebase, base: uint256, round_up: bool) -> uint256:
    """
    @param total - The Rebase which should be used to derive the relative elastic value
    @param base - The base value to convert to a relative elastic value
    @param round_up - Self explanatory
    """
    if total.base == 0:
        # If base is 0, then Rebase would be n/n, so elastic = base
        return base
    else:
        # Elastic is equal to base * (total.elastic / total.base), essentially a ratio
        elastic: uint256 = (base * convert(total.elastic, uint256)) / convert(
            total.base, uint256
        )

        # mamushi: Exhibit 2
        if round_up and (
            (
                (elastic * convert(total.base, uint256))
                / convert(total.elastic, uint256)
            )
            < base
        ):
            elastic = elastic + 1

        return elastic


@internal
def add_round_up(_total: Rebase, elastic: uint256) -> (Rebase, uint256):
    """
    @notice Add `elastic` to `total` and doubles `total.base`

    @param _total - The current total
    @param elastic - The elastic value to add to the rebase
    @param round_up - Self explanatory

    @return - The new Rebase total
    @return - The base in relationship to the elastic value
    """
    total: Rebase = _total
    base: uint256 = self.to_base_round_up(total, elastic)
    total.elastic += convert(elastic, uint128)
    total.base += convert(base, uint128)
    return (total, base)


@internal
def sub(_total: Rebase, base: uint256, round_up: bool) -> (Rebase, uint256):
    """
    @param _total - The current total
    @param base - The base value to subtract from the rebase total
    @param round_up - Self explanatory

    @return - The new Rebase total
    @return - The elastic in relationship to the base value
    """
    total: Rebase = _total
    elastic: uint256 = self.to_elastic(total, base, round_up)
    total.elastic -= convert(elastic, uint128)
    total.base -= convert(base, uint128)
    return (total, elastic)


# ///////////////////////////////////////////////////// #
#		      Math Helper For Precision					#
# ///////////////////////////////////////////////////// #
# Ty snekmate again
@pure
@internal
def mul_div(
    x: uint256, y: uint256, denominator: uint256, roundup: bool
) -> uint256:
    """
    @dev Calculates "(x * y) / denominator" in 512-bit precision,
         following the selected rounding direction.
    @notice The implementation is inspired by Remco Bloemen's
            implementation under the MIT license here:
            https://xn--2-umb.com/21/muldiv.
            Furthermore, the rounding direction design pattern is
            inspired by OpenZeppelin's implementation here:
            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.
    @param x The 32-byte multiplicand.
    @param y The 32-byte multiplier.
    @param denominator The 32-byte divisor.
    @param roundup The Boolean variable that specifies whether
           to round up or not. The default `False` is round down.
    @return uint256 The 32-byte calculation result.
    """
    # Handle division by zero.
    assert denominator != empty(uint256), "Math: mul_div division by zero"

    # 512-bit multiplication "[prod1 prod0] = x * y".
    # Compute the product "mod 2**256" and "mod 2**256 - 1".
    # Then use the Chinese Remainder theorem to reconstruct
    # the 512-bit result. The result is stored in two 256-bit
    # variables, where: "product = prod1 * 2**256 + prod0".
    mm: uint256 = uint256_mulmod(x, y, max_value(uint256))
    # The least significant 256 bits of the product.
    prod0: uint256 = unsafe_mul(x, y)
    # The most significant 256 bits of the product.
    prod1: uint256 = empty(uint256)

    if mm < prod0:
        prod1 = unsafe_sub(unsafe_sub(mm, prod0), 1)
    else:
        prod1 = unsafe_sub(mm, prod0)

    if prod1 == empty(uint256):
        if roundup and uint256_mulmod(x, y, denominator) != empty(uint256):
            # Calculate "ceil((x * y) / denominator)". The following
            # line cannot overflow because we have the previous check
            # "(x * y) % denominator != 0", which accordingly rules out
            # the possibility of "x * y = 2**256 - 1" and `denominator == 1`.
            return unsafe_add(unsafe_div(prod0, denominator), 1)
        else:
            return unsafe_div(prod0, denominator)

    # Ensure that the result is less than 2**256. Also,
    # prevents that `denominator == 0`.
    assert denominator > prod1, "Math: mul_div overflow"

    #######################
    # 512 by 256 Division #
    #######################

    # Make division exact by subtracting the remainder
    # from "[prod1 prod0]". First, compute remainder using
    # the `uint256_mulmod` operation.
    remainder: uint256 = uint256_mulmod(x, y, denominator)

    # Second, subtract the 256-bit number from the 512-bit
    # number.
    if remainder > prod0:
        prod1 = unsafe_sub(prod1, 1)
    prod0 = unsafe_sub(prod0, remainder)

    # Factor powers of two out of the denominator and calculate
    # the largest power of two divisor of denominator. Always `>= 1`,
    # unless the denominator is zero (which is prevented above),
    # in which case `twos` is zero. For more details, please refer to:
    # https://cs.stackexchange.com/q/138556.
    twos: uint256 = unsafe_sub(0, denominator) & denominator
    # Divide denominator by `twos`.
    denominator_div: uint256 = unsafe_div(denominator, twos)
    # Divide "[prod1 prod0]" by `twos`.
    prod0 = unsafe_div(prod0, twos)
    # Flip `twos` such that it is "2**256 / twos". If `twos` is zero,
    # it becomes one.
    twos = unsafe_add(unsafe_div(unsafe_sub(empty(uint256), twos), twos), 1)

    # Shift bits from `prod1` to `prod0`.
    prod0 |= unsafe_mul(prod1, twos)

    # Invert the denominator "mod 2**256". Since the denominator is
    # now an odd number, it has an inverse modulo 2**256, so we have:
    # "denominator * inverse = 1 mod 2**256". Calculate the inverse by
    # starting with a seed that is correct for four bits. That is,
    # "denominator * inverse = 1 mod 2**4".
    inverse: uint256 = unsafe_mul(3, denominator_div) ^ 2

    # Use Newton-Raphson iteration to improve accuracy. Thanks to Hensel's
    # lifting lemma, this also works in modular arithmetic by doubling the
    # correct bits in each step.
    inverse = unsafe_mul(
        inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))
    )  # Inverse "mod 2**8".
    inverse = unsafe_mul(
        inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))
    )  # Inverse "mod 2**16".
    inverse = unsafe_mul(
        inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))
    )  # Inverse "mod 2**32".
    inverse = unsafe_mul(
        inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))
    )  # Inverse "mod 2**64".
    inverse = unsafe_mul(
        inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))
    )  # Inverse "mod 2**128".
    inverse = unsafe_mul(
        inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))
    )  # Inverse "mod 2**256".

    # Since the division is now exact, we can divide by multiplying
    # with the modular inverse of the denominator. This returns the
    # correct result modulo 2**256. Since the preconditions guarantee
    # that the result is less than 2**256, this is the final result.
    # We do not need to calculate the high bits of the result and
    # `prod1` is no longer necessary.
    result: uint256 = unsafe_mul(prod0, inverse)

    if roundup and uint256_mulmod(x, y, denominator) != empty(uint256):
        # Calculate "ceil((x * y) / denominator)". The following
        # line uses intentionally checked arithmetic to prevent
        # a theoretically possible overflow.
        result += 1

    return result


# ///////////////////////////////////////////////////// #
#						Interfaces						#
# ///////////////////////////////////////////////////// #

# Oracle Interface
interface IOracle:
    def get() -> (bool, uint256): nonpayable


# Factory Interface
interface ICogFactory:
    def fee_to() -> address: view


# Cog Pair Specific Events
event AddCollateral:
    to: indexed(address)
    amount: indexed(uint256)
    user_collateral_share: indexed(uint256)


event RemoveCollateral:
    to: indexed(address)
    amount: indexed(uint256)
    user_collateral_share: indexed(uint256)

event Borrow:
    amount: indexed(uint256)
    to: indexed(address)
    _from: indexed(address)


event Paused:
    time: indexed(uint256)


event UnPaused:
    time: indexed(uint256)


# ERC20 Events

event Transfer:
    sender: indexed(address)
    receiver: indexed(address)
    amount: uint256


event Approval:
    owner: indexed(address)
    spender: indexed(address)
    allowance: uint256


# ERC4626 Events

event Deposit:
    depositor: indexed(address)
    receiver: indexed(address)
    assets: uint256
    shares: uint256


event Withdraw:
    withdrawer: indexed(address)
    receiver: indexed(address)
    owner: indexed(address)
    assets: uint256
    shares: uint256


# ///////////////////////////////////////////////////// #
#                 State Variables	                    #
# ///////////////////////////////////////////////////// #

oracle: public(immutable(address))  # Address of the oracle
asset: public(immutable(address))  # Address of the asset
collateral: public(immutable(address))  # Address of the collateral

total_collateral_share: public(
    uint256
)  # Total collateral share of all borrowers
total_asset: public(
    Rebase
)  # Numerator is amount asset total, denominator keeps track of total shares of the asset
total_borrow: public(
    Rebase
)  # Numerator is the amount owed total, denominator keeps track of initial borrow shares owed

user_collateral_share: public(
    HashMap[address, uint256]
)  # Collateral share of each user

user_borrow_part: public(
    HashMap[address, uint256]
)  # Borrow ""share"" of each user

exchange_rate: public(uint256)  # Exchange rate between asset and collateral


struct AccrueInfo:
        interest_per_second: uint64
        last_accrued: uint64
        fees_earned_fraction: uint128


struct SurgeInfo:
        last_interest_per_second: uint64
        last_elapsed_time: uint64


accrue_info: public(AccrueInfo)

surge_info: public(SurgeInfo)

factory: public(immutable(address))  # Address of the factory
paused: public(bool)  # Status of if the pool is paused

# ///////////////////////////////////////////////////// #
#                  Configuration Constants              #
# ///////////////////////////////////////////////////// #
# SAFETY : EXCHANGE_RATE_PRECISION strictly must be > COLLATERIZATION_RATE_PRECISION or a divide by zero error will occur
# NOTE: Given they are also divided by each other, consider any potential precision loss as well
EXCHANGE_RATE_PRECISION: constant(uint256) = 1000000000000000000  # 1e18

COLLATERIZATION_RATE_PRECISION: constant(uint256) = 100000  # 1e5
COLLATERIZATION_RATE: constant(uint256) = 85000  # 85%

BORROW_OPENING_FEE: public(uint256)
BORROW_OPENING_FEE_PRECISION: constant(uint256) = 100000

# Starts at 10%, raised when PoL only mode is activated to PROTOCOL_FEE_PRECISION or 100%
protocol_fee: public(uint256)

DEFAULT_PROTOCOL_FEE: public(uint256)
PROTOCOL_FEE_PRECISION: constant(uint256) = 1000000

# If IR surges ~10% in 1 day then Protocol begins accruing PoL
# dr/dt, where dt = 3 days (86400 * 3), and dr is change in interest_rate per second or 3170979200 (5% interest rate)
PROTOCOL_SURGE_THRESHOLD: constant(uint64) = 1635979200
SURGE_DURATION: constant(uint64) = 86400 * 3 # 3 Days
UTILIZATION_PRECISION: constant(uint256) = 1000000000000000000  # 1e18
MINIMUM_TARGET_UTILIZATION: immutable(uint256)
MAXIMUM_TARGET_UTILIZATION: immutable(uint256)
FACTOR_PRECISION: constant(uint256) = 1000000000000000000  # 1e18

STARTING_INTEREST_PER_SECOND: immutable(uint64)
MINIMUM_INTEREST_PER_SECOND: immutable(uint64)
MAXIMUM_INTEREST_PER_SECOND: immutable(uint64)
INTEREST_ELASTICITY: immutable(uint256)

LIQUIDATION_MULTIPLIER: constant(uint256) = 112000  # 12
LIQUIDATION_MULTIPLIER_PRECISION: constant(uint256) = 100000  # 1e5

INTEREST_PER_SECOND_PRECISION: constant(uint256) = 1000000000000000000 # 1e18

# //////////////////////////////////////////////////////////////// #
#                              ERC20                               #
# //////////////////////////////////////////////////////////////// #
balanceOf: public(HashMap[address, uint256])


@view
@external
def totalSupply() -> uint256:
    """
    @return - Returns the total supply of the Asset Token, which is also the total number of shares
    """
    return convert(self.total_asset.base, uint256)


allowance: public(HashMap[address, HashMap[address, uint256]])

NAME: constant(String[17]) = "Cog Pool LP Token"


@view
@external
def name() -> String[17]:
    """
    @return The name for the ERC4626 Vault Token
    """
    return NAME


SYMBOL: constant(String[3]) = "CLP"


@view
@external
def symbol() -> String[3]:
    """
    @return The token symbol for the ERC4626 Vault Token
    """
    return SYMBOL


DECIMALS: constant(uint8) = 18


@view
@external
def decimals() -> uint8:
    """
    @return The number of decimals for the ERC4626 Vault Token
    """
    return DECIMALS


@external
def transfer(receiver: address, amount: uint256) -> bool:
    self.balanceOf[msg.sender] -= amount
    self.balanceOf[receiver] += amount
    log Transfer(msg.sender, receiver, amount)
    return True


@external
def approve(spender: address, amount: uint256) -> bool:
    self.allowance[msg.sender][spender] = amount
    log Approval(msg.sender, spender, amount)
    return True


@external
def transferFrom(sender: address, receiver: address, amount: uint256) -> bool:
    self.allowance[sender][msg.sender] -= amount
    self.balanceOf[sender] -= amount
    self.balanceOf[receiver] += amount
    log Transfer(sender, receiver, amount)
    return True


# @t11s said I didn't need to support permit (https://twitter.com/transmissions11/status/1673478816168296450), so I removed it, if you need permit for something make a wrapper contract
# that kind of sounds like you problem tbh, it's just an LP token, make your users use 2 clicks it's not that hard

# ///////////////////////////////////////////////////// #
#		            ERC4626 Compatibility	        	#
# ///////////////////////////////////////////////////// #

@view
@external
def totalAssets() -> uint256:
    """
    @return - Returns the total amount of assets owned by the vault
    """
    total_assets_elastic: uint256 = convert(self.total_asset.elastic, uint256)
    # Borrowed assets are subtracted from the above total, so combined elastic values of both
    # total borrow and total assets should be the same
    total_borrow_elastic: uint256 = convert(self.total_borrow.elastic, uint256)
    # Interest is the difference between elastic and base, since they start at 1:1
    return total_borrow_elastic + total_assets_elastic


@view
@external
def convertToAssets(shareAmount: uint256) -> uint256:
    """
    @param shareAmount - The amount of shares to convert to assets
    @return - Returns the amount of assets returned given the amount of shares
    """
    return self._convertToAssets(shareAmount)


@view
@internal
def _convertToAssets(shareAmount: uint256) -> uint256:
    _total_asset: Rebase = self.total_asset
    if _total_asset.base == 0:
        # Shares mint 1:1 at the start until interest accrues
        return shareAmount
    all_share: uint256 = convert(
        _total_asset.elastic + self.total_borrow.elastic, uint256
    )
    return shareAmount * all_share / convert(_total_asset.base, uint256)


@view
@external
def convertToShares(assetAmount: uint256) -> uint256:
    """
    @param assetAmount - The amount of assets to convert to shares
    @return - Returns the amount of shares returned given the amount of assets
    """
    return self._convertToShares(assetAmount)


@view
@internal
def _convertToShares(assetAmount: uint256) -> uint256:
    total_asset_base: uint256 = convert(self.total_asset.base, uint256)
    all_share: uint256 = convert(
        self.total_asset.elastic + self.total_borrow.elastic, uint256
    )
    if all_share == 0:
        # Shares mint 1:1 at the start until interest accrues
        return assetAmount
    return assetAmount * total_asset_base / all_share


@view
@external
def maxDeposit(receiver: address) -> uint256:
    """
    @param receiver - The address of the receiver
    @return - Returns the maximum amount of assets that can be deposited into the vault
    @notice - While technically there is no deposit cap, at unreasonably large uint256 values this may revert
    """
    return max_value(uint256)


@view
@external
def previewDeposit(assets: uint256) -> uint256:
    """
    @param assets - The amount of assets to deposit
    @return - Returns the amount of shares that would be minted if the assets were deposited
    """
    return self._convertToShares(assets)


@external
def deposit(assets: uint256, receiver: address = msg.sender) -> uint256:
    """
    @param assets - The amount of assets to deposit
    @param receiver - The address of the receiver

    @return - Returns the amount of shares minted for the deposit
    """
    self._is_not_paused()
    shares_out: uint256 = self._add_asset(receiver, assets)
    log Deposit(msg.sender, receiver, assets, shares_out)

    return shares_out


@view
@external
def maxMint(owner: address) -> uint256:
    """
    @notice no cap on max amount of shares to mint except at unreasonably high uint256 values
    """
    return max_value(uint256)


@view
@external
def previewMint(shares: uint256) -> uint256:
    """
    @param shares - The amount of shares to mint
    @return - Returns the amount of assets required to mint the specified amount of shares
    """
    # Convert shares to assets
    return self._convertToAssets(shares)


@external
def mint(shares: uint256, receiver: address = msg.sender) -> uint256:
    """
    @param shares - The amount of shares to mint
    @param receiver - The address of the receiver

    @return - The amount of assets used
    """
    self._is_not_paused()
    tokens_to_deposit: uint256 = self._convertToAssets(shares)
    shares_out: uint256 = self._add_asset(receiver, tokens_to_deposit)
    log Deposit(msg.sender, receiver, tokens_to_deposit, shares_out)

    return tokens_to_deposit


@view
@external
def maxWithdraw(owner: address) -> uint256:
    """
    @param owner - The address of the owner
    @return - Returns the maximum amount of assets that can be withdrawn from the vault
    """
    return min(
        self._convertToAssets(self.balanceOf[owner]),
        ERC20(asset).balanceOf(self),
    )


@view
@external
def previewWithdraw(assets: uint256) -> uint256:
    """
    @param assets - The amount of assets to withdraw
    @return - The amount of shares worth withdrawn
    @notice - Will revert if you try to preview withdrawing more assets than available currently in the vault's balance
    """
    return min(self._convertToShares(assets), self._convertToShares(ERC20(asset).balanceOf(self)))


@external
def withdraw(
    assets: uint256, receiver: address = msg.sender, owner: address = msg.sender
) -> uint256:
    """
    @param assets - The amount of assets to withdraw
    @param receiver - Reciever of the assets withdrawn
    @param owner - The owners whose assets should be withdrawn

    @return - The amount of shares burned
    """
    self.efficient_accrue()
    shares: uint256 = self._convertToShares(assets)
    assets_withdraw: uint256 = self._remove_asset(receiver, owner, shares)
    log Withdraw(msg.sender, receiver, owner, assets, shares)

    return shares


@view
@external
def maxRedeem(owner: address) -> uint256:
    """
    @param owner - The address of the owner
    @return - Returns the maximum amount of shares that can be redeemed from the vault by the owner
    """
    return min(
        self.balanceOf[owner],
        self._convertToShares(ERC20(asset).balanceOf(self)),
    )


@view
@external
def previewRedeem(shares: uint256) -> uint256:
    """
    @param shares - The amount of shares to redeem
    @return - Returns the amount of assets that would be returned if the shares were redeemed
    """
    return min(
        self._convertToAssets(shares),
        self._convertToShares(ERC20(asset).balanceOf(self)),
    )


@external
def redeem(
    shares: uint256, receiver: address = msg.sender, owner: address = msg.sender
) -> uint256:
    """
    @param shares - The amount of shares to redeem
    @param receiver - The address of the receiver
    @param owner - The address of the owner

    @return - The amount of assets returned
    """
    self.efficient_accrue()
    assets_out: uint256 = self._remove_asset(receiver, owner, shares)
    
    log Withdraw(msg.sender, receiver, owner, assets_out, shares)

    return assets_out


# ///////////////////////////////////////////////////// #
# 		        Internal Implementations	         	#
# ///////////////////////////////////////////////////// #
@internal
def _is_not_paused():
    assert (not self.paused), "Pair Paused"


@internal
def efficient_accrue():
    _accrue_info: AccrueInfo = self.accrue_info
    elapsed_time: uint256 = block.timestamp - convert(
        _accrue_info.last_accrued, uint256
    )
    if elapsed_time == 0:
        # Prevents re-executing this logic if multiple actions are taken in the same block
        return

    self._accrue(_accrue_info, elapsed_time)


@internal
def _accrue(accrue_info: AccrueInfo, elapsed_time: uint256):
    _accrue_info: AccrueInfo = accrue_info
    _accrue_info.last_accrued = convert(block.timestamp, uint64)

    _total_borrow: Rebase = self.total_borrow
    if _total_borrow.base == 0:
        # If there are no outstanding borrows, there is no need to accrue interest, and interest
        # rate should be moved to minimum to encourage borrowing
        if _accrue_info.interest_per_second != STARTING_INTEREST_PER_SECOND:
            _accrue_info.interest_per_second = STARTING_INTEREST_PER_SECOND
        self.accrue_info = _accrue_info
        return

    interest_accrued: uint256 = 0
    fee_fraction: uint256 = 0
    _total_asset: Rebase = self.total_asset

    # Accrue interest
    interest_accrued = (
        convert(_total_borrow.elastic, uint256)
        * convert(_accrue_info.interest_per_second, uint256)
        * elapsed_time
        / INTEREST_PER_SECOND_PRECISION
    )  

    _total_borrow.elastic = _total_borrow.elastic + convert(
        interest_accrued, uint128
    )

    full_asset_amount: uint256 = convert(
        _total_asset.elastic, uint256
    ) + convert(_total_borrow.elastic, uint256)

    # Calculate fees
    fee_amount: uint256 = (
        interest_accrued * self.protocol_fee / PROTOCOL_FEE_PRECISION
    )  # % of interest paid goes to fee

    fee_fraction = (
        fee_amount * convert(_total_asset.base, uint256) / full_asset_amount
    )  # Update total fees earned
    _accrue_info.fees_earned_fraction = (
        _accrue_info.fees_earned_fraction + convert(fee_fraction, uint128)
    )

    # Fees should be considered in total assets
    self.total_asset.base = _total_asset.base + convert(fee_fraction, uint128)

    # Write new total borrow state to storage
    self.total_borrow = _total_borrow

    # Update interest rate
    utilization: uint256 = (
        convert(_total_borrow.elastic, uint256)
        * UTILIZATION_PRECISION
        / full_asset_amount
    )

    if utilization < MINIMUM_TARGET_UTILIZATION:
        under_factor: uint256 = (
            (MINIMUM_TARGET_UTILIZATION - utilization)
            * FACTOR_PRECISION
            / MINIMUM_TARGET_UTILIZATION
        )
        scale: uint256 = INTEREST_ELASTICITY + (
            under_factor * under_factor * elapsed_time
        )
        new_interest_per_second: uint64 = convert(
            convert(_accrue_info.interest_per_second, uint256)
            * INTEREST_ELASTICITY
            / scale,
            uint64,
        )
        _accrue_info.interest_per_second = new_interest_per_second

        if _accrue_info.interest_per_second < MINIMUM_INTEREST_PER_SECOND:
            _accrue_info.interest_per_second = (MINIMUM_INTEREST_PER_SECOND)
    elif utilization > MAXIMUM_TARGET_UTILIZATION:
        over_factor: uint256 = (
            (utilization - MAXIMUM_TARGET_UTILIZATION)
            * FACTOR_PRECISION
            / MAXIMUM_TARGET_UTILIZATION
        )
        scale: uint256 = INTEREST_ELASTICITY + (
            over_factor * over_factor * elapsed_time
        )
        new_interest_per_second: uint64 = convert(
            convert(_accrue_info.interest_per_second, uint256)
            * scale
            / INTEREST_ELASTICITY,
            uint64,
        )
        _accrue_info.interest_per_second = new_interest_per_second

        if new_interest_per_second > MAXIMUM_INTEREST_PER_SECOND:
            _accrue_info.interest_per_second = (MAXIMUM_INTEREST_PER_SECOND)
    dt: uint64 = (
        convert(block.timestamp, uint64) - self.surge_info.last_elapsed_time
    )
    if dt > SURGE_DURATION:
        # if interest rate is increasing
        if (
            _accrue_info.interest_per_second
            > self.surge_info.last_interest_per_second
        ):
            # If daily change in interest rate is greater than Surge threshold, trigger surge breaker
            dr: uint64 = (
                _accrue_info.interest_per_second
                - self.surge_info.last_interest_per_second
            )
            if dr > PROTOCOL_SURGE_THRESHOLD:
                self.surge_info.last_elapsed_time = convert(
                    block.timestamp, uint64
                )
                self.surge_info.last_interest_per_second = (
                    _accrue_info.interest_per_second
                )
                # PoL Should accrue here, instead of to lenders, to discourage pid attacks as described in https://gauntlet.network/reports/pid
                self.protocol_fee = PROTOCOL_FEE_PRECISION  # 100% Protocol Fee
        else:
            # Reset protocol fee elsewise
            self.protocol_fee = self.DEFAULT_PROTOCOL_FEE  # 10% Protocol Fee
    self.accrue_info = _accrue_info


@internal
def _add_collateral(to: address, amount: uint256):
    """
    @param to The address to add collateral for
    @param amount The amount of collateral to add, in tokens
    """
    new_collateral_share: uint256 = self.user_collateral_share[to] + amount
    self.user_collateral_share[to] = new_collateral_share
    old_total_collateral_share: uint256 = self.total_collateral_share
    self.total_collateral_share = old_total_collateral_share + amount
    assert ERC20(collateral).transferFrom(
        msg.sender, self, amount, default_return_value=True
    )  # dev: Transfer Failed

    log AddCollateral(to, amount, new_collateral_share)


@internal
def _remove_collateral(to: address, amount: uint256):
    """
    @param to The address to remove collateral for
    @param amount The amount of collateral to remove, in tokens
    """
    new_collateral_share: uint256 = self.user_collateral_share[msg.sender] - amount
    self.user_collateral_share[msg.sender] = new_collateral_share
    self.total_collateral_share = self.total_collateral_share - amount
    assert ERC20(collateral).transfer(
        to, amount, default_return_value=True
    )  # dev: Transfer Failed

    log RemoveCollateral(to, amount, new_collateral_share)


@internal
def _add_asset(to: address, amount: uint256) -> uint256:
    """
    @param to The address to add asset for
    @param amount The amount of asset to add, in tokens
    @return The amount of shares minted
    """
    _total_asset: Rebase = self.total_asset
    all_share: uint256 = convert(
        _total_asset.elastic + self.total_borrow.elastic, uint256
    )
    fraction: uint256 = 0
    if all_share == 0:
        fraction = amount
    else:
        fraction = (amount * convert(_total_asset.base, uint256)) / all_share
    if _total_asset.base + convert(fraction, uint128) < 1000:
        return 0

    self.total_asset = Rebase(
        {
            elastic: self.total_asset.elastic + convert(amount, uint128),
            base: self.total_asset.base + convert(fraction, uint128),
        }
    )

    new_balance: uint256 = self.balanceOf[to] + fraction
    self.balanceOf[to] = new_balance

    assert ERC20(asset).transferFrom(
        msg.sender, self, amount, default_return_value=True
    )  # dev: Transfer Failed

    return fraction


@internal
def _remove_asset(to: address, owner: address, share: uint256) -> uint256:
    """
    @param to The address to remove asset for
    @param share The amount of asset to remove, in shares
    @return The amount of assets removed
    """
    if owner != msg.sender:
        assert (
            self.allowance[owner][msg.sender] >= share
        ), "Insufficient Allowance"
        self.allowance[owner][msg.sender] -= share

    _total_asset: Rebase = self.total_asset
    all_share: uint256 = convert(
        _total_asset.elastic + self.total_borrow.elastic, uint256
    )
    amount: uint256 = (share * all_share) / convert(_total_asset.base, uint256)

    _total_asset.elastic -= convert(amount, uint128)
    _total_asset.base -= convert(share, uint128)
    assert _total_asset.base >= 1000, "Below Minimum"
    self.total_asset = _total_asset

    new_balance: uint256 = self.balanceOf[owner] - share
    self.balanceOf[owner] = new_balance
    assert ERC20(asset).transfer(
        to, amount, default_return_value=True
    )  # dev: Transfer Failed

    return amount


@internal
def _update_exchange_rate() -> (bool, uint256):
    """
    @return A tuple of (updated, rate)
        updated: Whether the exchange rate was updated
        rate: The exchange rate
    """
    updated: bool = False
    rate: uint256 = 0

    updated, rate = IOracle(oracle).get()

    if updated:
        self.exchange_rate = rate
    else:
        rate = self.exchange_rate

    return (updated, rate)


@internal
def _borrow(amount: uint256, _from: address, to: address) -> uint256:
    """
    @param amount: The amount of asset to borrow, in tokens
    @param _from: The account whom the loan should be taken out against
    @param to: The address to send the borrowed tokens to
    @return: The amount of tokens borrowed
    """
    self._update_exchange_rate()
    fee_amount: uint256 = (
        amount * self.BORROW_OPENING_FEE
    ) / BORROW_OPENING_FEE_PRECISION

    temp_total_borrow: Rebase = Rebase(
        {
            elastic: 0,
            base: 0,
        }
    )
    part: uint256 = 0

    temp_total_borrow, part = self.add_round_up(
        self.total_borrow, (amount + fee_amount)
    )
    self.total_borrow = temp_total_borrow
    self.user_borrow_part[_from] = self.user_borrow_part[_from] + part

    _total_asset: Rebase = self.total_asset
    assert _total_asset.base >= 1000, "Below Minimum"
    _total_asset.elastic = convert(
        convert(_total_asset.elastic, uint256) - amount, uint128
    )
    self.total_asset = _total_asset
    assert ERC20(asset).transfer(
        to, amount, default_return_value=True
    )  # dev: Transfer Failed

    log Borrow(amount, to, _from)

    return amount


@internal
def _repay(payment: uint256) -> uint256:
    """
    @param payment: The amount of asset to repay, in shares of the borrow position
    @return: The amount of tokens repaid in shares
    """
    temp_total_borrow: Rebase = Rebase(
        {
            elastic: 0,
            base: 0,
        }
    )
    amount: uint256 = 0

    temp_total_borrow, amount = self.sub(self.total_borrow, payment, True)
    self.total_borrow = temp_total_borrow

    self.user_borrow_part[msg.sender] = self.user_borrow_part[msg.sender] - payment
    total_share: uint128 = self.total_asset.elastic
    assert ERC20(asset).transferFrom(
        msg.sender, self, amount, default_return_value=True
    )  # dev: Transfer Failed

    self.total_asset.elastic = total_share + convert(amount, uint128)
    return amount


@internal
def _is_solvent(user: address, exchange_rate: uint256) -> bool:
    """
    @param user: The user to check
    @param exchange_rate: The exchange rate to use
    @return: Whether the user is solvent
    """
    borrow_part: uint256 = self.user_borrow_part[user]
    if borrow_part == 0:
        return True
    collateral_share: uint256 = self.user_collateral_share[user]
    if collateral_share == 0:
        return False

    _total_borrow: Rebase = self.total_borrow
    collateral_amt: uint256 = (
        (
            collateral_share
            * (EXCHANGE_RATE_PRECISION / COLLATERIZATION_RATE_PRECISION)
        )
        * COLLATERIZATION_RATE
    )

    borrow_part = self.mul_div(
        (borrow_part * convert(_total_borrow.elastic, uint256)),
        exchange_rate,
        convert(_total_borrow.base, uint256),
        False,
    )
    return collateral_amt >= borrow_part


# ///////////////////////////////////////////////////// #
# 				External Implementations				#
# ///////////////////////////////////////////////////// #
@external
def __init__(
    _asset: address,
    _collateral: address,
    _oracle: address,
    min_target_utilization: uint256,
    max_target_utilization: uint256,
    starting_interest_per_second: uint64,
    min_interest: uint64,
    max_interest: uint64,
    elasticity: uint256,
):
    assert (
        _collateral != 0x0000000000000000000000000000000000000000
    ), "Invalid Collateral"
    collateral = _collateral
    asset = _asset
    oracle = _oracle
    self.DEFAULT_PROTOCOL_FEE = 100000
    self.protocol_fee = 100000  # 10%
    MINIMUM_TARGET_UTILIZATION = min_target_utilization
    MAXIMUM_TARGET_UTILIZATION = max_target_utilization
    STARTING_INTEREST_PER_SECOND = starting_interest_per_second
    MINIMUM_INTEREST_PER_SECOND = min_interest
    MAXIMUM_INTEREST_PER_SECOND = max_interest
    INTEREST_ELASTICITY = elasticity
    self.BORROW_OPENING_FEE = 50
    factory = msg.sender


@external
def accrue():
    """
    @dev Accrues interest and updates the exchange rate if needed
    """
    self.efficient_accrue()


@external
def add_collateral(to: address, amount: uint256):
    """
    @param to The address to add collateral for
    @param amount The amount of collateral to add, in tokens
    """
    self.efficient_accrue()
    self._add_collateral(to, amount)


@external
def remove_collateral(to: address, amount: uint256):
    """
    @param to The address to remove collateral for
    @param amount The amount of collateral to remove, in tokens
    """
    self.efficient_accrue()
    self._remove_collateral(to, amount)
    assert self._is_solvent(
        msg.sender, self.exchange_rate
    ), "Insufficient Collateral"


borrow_approvals: public(HashMap[address, HashMap[address, uint256]])


@external
def approve_borrow(borrower: address, amount: uint256) -> bool:
    self.borrow_approvals[msg.sender][borrower] = amount
    log Approval(msg.sender, borrower, amount)
    return True


@external
def borrow(
    amount: uint256, _from: address = msg.sender, to: address = msg.sender
) -> uint256:
    """
    @param amount The amount of asset to borrow, in tokens
    @param _from The account whom the loan should be taken out against
    @param to The address to send the borrowed tokens to
    @return The amount of tokens borrowed
    """
    self._is_not_paused()
    self.efficient_accrue()
    if _from != msg.sender:
        self.borrow_approvals[_from][msg.sender] -= amount
    borrowed: uint256 = self._borrow(amount, _from, to)
    assert self._is_solvent(
        _from, self.exchange_rate
    ), "Insufficient Collateral"
    # Now that utilization has changed, interest must be accrued to trigger any surge which now may be occuring
    self._accrue(self.accrue_info, 0)
    return borrowed


@external
def repay(payment: uint256) -> uint256:
    """
    @param payment The amount of asset to repay, in debt position shares
    @return The amount of tokens repaid in shares
    """
    self.efficient_accrue()
    return self._repay(payment)


@external
def get_exchange_rate() -> (bool, uint256):
    """
    @return A tuple of (updated, rate)
        updated Whether the exchange rate was updated
        rate The exchange rate
    """
    return self._update_exchange_rate()


@external
def liquidate(user: address, max_borrow_parts: uint256, to: address):
    """
    @param user The user to liquidate
    @param max_borrow_parts The parts to liquidate
    @param to The address to send the liquidated tokens to
    """
    exchange_rate: uint256 = 0
    updated: bool = False  # Never used
    updated, exchange_rate = self._update_exchange_rate()
    self.efficient_accrue()

    collateral_share: uint256 = 0
    borrow_amount: uint256 = 0
    borrow_part: uint256 = 0
    _total_borrow: Rebase = self.total_borrow

    if not self._is_solvent(user, exchange_rate):
        available_borrow_part: uint256 = self.user_borrow_part[user]
        borrow_part = min(max_borrow_parts, available_borrow_part)
        self.user_borrow_part[user] = available_borrow_part - borrow_part

        borrow_amount = self.to_elastic(
            _total_borrow, borrow_part, False
        )

        collateral_share = (
            (borrow_amount * LIQUIDATION_MULTIPLIER * exchange_rate)
            / (LIQUIDATION_MULTIPLIER_PRECISION * EXCHANGE_RATE_PRECISION)
        )

        # NOTE: If this check is ever true, bad debt has accrued, and so the
        # liquidator will instead receive collateral worth less than the assets 
        # they are paying, but the bad debt position will be resolved assuming the entire bad debt
        # position is liquidated. Allows for bad debt positions to be liquidated
        if collateral_share > self.user_collateral_share[user] and borrow_part == available_borrow_part:
            collateral_share = self.user_collateral_share[user]
       
        self.user_collateral_share[user] = (
            self.user_collateral_share[user] - collateral_share
        )

    assert borrow_amount != 0, "CogPair: User is solvent"

    self.total_borrow.elastic = self.total_borrow.elastic - convert(
        borrow_amount, uint128
    )
    self.total_borrow.base = self.total_borrow.base - convert(
        borrow_part, uint128
    )

    self.total_collateral_share = (
        self.total_collateral_share - collateral_share
    )

    assert ERC20(collateral).transfer(
        to, collateral_share, default_return_value=True
    )  # dev: Transfer failed

    assert ERC20(asset).transferFrom(
        msg.sender, self, borrow_amount, default_return_value=True
    )  # dev: Transfer failed

    self.total_asset.elastic = self.total_asset.elastic + convert(
        borrow_amount, uint128
    )


# ///////////////////////////////////////////////////// #
# 				Tinkermaster Control Panel				#
# ///////////////////////////////////////////////////// #

@external
def update_borrow_fee(newFee: uint256):
    assert (msg.sender == factory)
    assert (
        newFee <= BORROW_OPENING_FEE_PRECISION / 2
    )  # Prevent rugging via borrow fee
    self.BORROW_OPENING_FEE = newFee


@external
def update_default_protocol_fee(newFee: uint256):
    assert (msg.sender == factory)
    assert (newFee <= PROTOCOL_FEE_PRECISION)
    self.DEFAULT_PROTOCOL_FEE = newFee


@external
def pause():
    assert (msg.sender == factory)
    self.paused = True
    log Paused(block.timestamp)


@external
def unpause():
    assert (msg.sender == factory)
    self.paused = False
    log UnPaused(block.timestamp)


@external
def roll_over_pol():
    """
    @dev Withdraws protocol fees and deposits them into the pool on behalf of the tinkermaster address
    """
    _fee_to: address = ICogFactory(factory).fee_to()
    _accrue_info: AccrueInfo = self.accrue_info

    # Withdraw protocol fees
    fees_earned_fraction: uint256 = convert(
        _accrue_info.fees_earned_fraction, uint256
    )
    self.balanceOf[_fee_to] = self.balanceOf[_fee_to] + fees_earned_fraction
    self.accrue_info.fees_earned_fraction = 0

    log Transfer(convert(0, address), _fee_to, fees_earned_fraction)

Contract Security Audit

Contract ABI

API
[{"name":"AddCollateral","inputs":[{"name":"to","type":"address","indexed":true},{"name":"amount","type":"uint256","indexed":true},{"name":"user_collateral_share","type":"uint256","indexed":true}],"anonymous":false,"type":"event"},{"name":"RemoveCollateral","inputs":[{"name":"to","type":"address","indexed":true},{"name":"amount","type":"uint256","indexed":true},{"name":"user_collateral_share","type":"uint256","indexed":true}],"anonymous":false,"type":"event"},{"name":"Borrow","inputs":[{"name":"amount","type":"uint256","indexed":true},{"name":"to","type":"address","indexed":true},{"name":"_from","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"Paused","inputs":[{"name":"time","type":"uint256","indexed":true}],"anonymous":false,"type":"event"},{"name":"UnPaused","inputs":[{"name":"time","type":"uint256","indexed":true}],"anonymous":false,"type":"event"},{"name":"Transfer","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"receiver","type":"address","indexed":true},{"name":"amount","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Approval","inputs":[{"name":"owner","type":"address","indexed":true},{"name":"spender","type":"address","indexed":true},{"name":"allowance","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Deposit","inputs":[{"name":"depositor","type":"address","indexed":true},{"name":"receiver","type":"address","indexed":true},{"name":"assets","type":"uint256","indexed":false},{"name":"shares","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Withdraw","inputs":[{"name":"withdrawer","type":"address","indexed":true},{"name":"receiver","type":"address","indexed":true},{"name":"owner","type":"address","indexed":true},{"name":"assets","type":"uint256","indexed":false},{"name":"shares","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"stateMutability":"view","type":"function","name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"name","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"symbol","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"decimals","inputs":[],"outputs":[{"name":"","type":"uint8"}]},{"stateMutability":"nonpayable","type":"function","name":"transfer","inputs":[{"name":"receiver","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"approve","inputs":[{"name":"spender","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"transferFrom","inputs":[{"name":"sender","type":"address"},{"name":"receiver","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"totalAssets","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"convertToAssets","inputs":[{"name":"shareAmount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"convertToShares","inputs":[{"name":"assetAmount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxDeposit","inputs":[{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewDeposit","inputs":[{"name":"assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"deposit","inputs":[{"name":"assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"deposit","inputs":[{"name":"assets","type":"uint256"},{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxMint","inputs":[{"name":"owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewMint","inputs":[{"name":"shares","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"mint","inputs":[{"name":"shares","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"mint","inputs":[{"name":"shares","type":"uint256"},{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxWithdraw","inputs":[{"name":"owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewWithdraw","inputs":[{"name":"assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"assets","type":"uint256"},{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"assets","type":"uint256"},{"name":"receiver","type":"address"},{"name":"owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxRedeem","inputs":[{"name":"owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewRedeem","inputs":[{"name":"shares","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"redeem","inputs":[{"name":"shares","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"redeem","inputs":[{"name":"shares","type":"uint256"},{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"redeem","inputs":[{"name":"shares","type":"uint256"},{"name":"receiver","type":"address"},{"name":"owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"constructor","inputs":[{"name":"_asset","type":"address"},{"name":"_collateral","type":"address"},{"name":"_oracle","type":"address"},{"name":"min_target_utilization","type":"uint256"},{"name":"max_target_utilization","type":"uint256"},{"name":"starting_interest_per_second","type":"uint64"},{"name":"min_interest","type":"uint64"},{"name":"max_interest","type":"uint64"},{"name":"elasticity","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"accrue","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"add_collateral","inputs":[{"name":"to","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"remove_collateral","inputs":[{"name":"to","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"approve_borrow","inputs":[{"name":"borrower","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"borrow","inputs":[{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"borrow","inputs":[{"name":"amount","type":"uint256"},{"name":"_from","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"borrow","inputs":[{"name":"amount","type":"uint256"},{"name":"_from","type":"address"},{"name":"to","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"repay","inputs":[{"name":"payment","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"get_exchange_rate","inputs":[],"outputs":[{"name":"","type":"bool"},{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"liquidate","inputs":[{"name":"user","type":"address"},{"name":"max_borrow_parts","type":"uint256"},{"name":"to","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"update_borrow_fee","inputs":[{"name":"newFee","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"update_default_protocol_fee","inputs":[{"name":"newFee","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"pause","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"unpause","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"roll_over_pol","inputs":[],"outputs":[]},{"stateMutability":"view","type":"function","name":"oracle","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"asset","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"collateral","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"total_collateral_share","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"total_asset","inputs":[],"outputs":[{"name":"","type":"tuple","components":[{"name":"elastic","type":"uint128"},{"name":"base","type":"uint128"}]}]},{"stateMutability":"view","type":"function","name":"total_borrow","inputs":[],"outputs":[{"name":"","type":"tuple","components":[{"name":"elastic","type":"uint128"},{"name":"base","type":"uint128"}]}]},{"stateMutability":"view","type":"function","name":"user_collateral_share","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"user_borrow_part","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"exchange_rate","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"accrue_info","inputs":[],"outputs":[{"name":"","type":"tuple","components":[{"name":"interest_per_second","type":"uint64"},{"name":"last_accrued","type":"uint64"},{"name":"fees_earned_fraction","type":"uint128"}]}]},{"stateMutability":"view","type":"function","name":"surge_info","inputs":[],"outputs":[{"name":"","type":"tuple","components":[{"name":"last_interest_per_second","type":"uint64"},{"name":"last_elapsed_time","type":"uint64"}]}]},{"stateMutability":"view","type":"function","name":"factory","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"paused","inputs":[],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"BORROW_OPENING_FEE","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"protocol_fee","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"DEFAULT_PROTOCOL_FEE","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"balanceOf","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"allowance","inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"borrow_approvals","inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"outputs":[{"name":"","type":"uint256"}]}]

612f53515034610165576020612fb35f395f518060a01c610165576040526020612fd35f395f518060a01c610165576060526020612ff35f395f518060a01c6101655760805260206130535f395f518060401c6101655760a05260206130735f395f518060401c6101655760c05260206130935f395f518060401c6101655760e0526060516100ea576012610100527f496e76616c696420436f6c6c61746572616c00000000000000000000000000006101205261010050610100518061012001601f825f031636823750506308c379a060c052602060e052601f19601f61010051011660440160dcfd5b606051612e7352604051612e5352608051612e3352620186a0601055620186a0600f5560206130135f395f51612eb35260206130335f395f51612ed35260a051612ef35260c051612f135260e051612f335260206130b35f395f51612f53526032600e5533612e9352612e3361016961000039612f73610000f35b5f80fd5f3560e01c6002603a820660011b612dbf01601e395f51565b637dc0d1d081186117655734612dbb576020612e3360403960206040f3611765565b6338d52e0f81186100585734612dbb576020612e5360403960206040f35b63dba2d553811861176557602436103417612dbb576020612e935f395f513318612dbb5761c35060043511612dbb57600435600e5500611765565b63d8dfeb4581186100b15734612dbb576020612e7360403960206040f35b6306fdde03811861012f5734612dbb5760208060805260116040527f436f6720506f6f6c204c5020546f6b656e00000000000000000000000000000060605260408160800181518152602082015160208201528051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b63f8ba4cff81186117655734612dbb57610147612440565b00611765565b631ac0e29281186101685734612dbb575f5460405260206040f35b63fe9f6e2481186117655734612dbb5760406101856101206128f7565b610120f3611765565b636b8833c981186117655734612dbb5760015460405260025460605260406040f3611765565b638274109781186117655734612dbb5760035460405260045460605260406040f3611765565b632b5fca1d811861021557602436103417612dbb576004358060a01c612dbb5760405260056040516020525f5260405f205460605260206060f35b6323b872dd811861176557606436103417612dbb576004358060a01c612dbb576040526024358060a01c612dbb5760605260126040516020525f5260405f2080336020525f5260405f2090508054604435808203828111612dbb579050905081555060116040516020525f5260405f208054604435808203828111612dbb579050905081555060116060516020525f5260405f208054604435808201828110612dbb57905090508155506060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60443560805260206080a3600160805260206080f3611765565b6377917072811861033b57602436103417612dbb576004358060a01c612dbb5760405260066040516020525f5260405f205460605260206060f35b634c01b790811861176557604436103417612dbb576004358060a01c612dbb576040526024356013336020525f5260405f20806040516020525f5260405f20905055604051337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560243560605260206060a3600160605260206060f3611765565b63171ef0b281186103d85734612dbb5760075460405260206040f35b63648c587481186103f45734612dbb5760105460405260206040f35b634b3fd148811861176557604436103417612dbb576024358060a01c612dbb5761034052336103605261118956611765565b633f0bc5bc811861044e5734612dbb57600854604052600954606052600a5460805260606040f35b6316552732811861046a5734612dbb57600f5460405260206040f35b6307a2d13a811861176557602436103417612dbb57602060043560405261049160c0611cd6565b60c0f3611765565b6363eded9581186117655734612dbb57600b54604052600c5460605260406040f3611765565b63c45a015581186117655734612dbb576020612e9360403960206040f3611765565b635c975abb81186117655734612dbb57600d5460405260206040f3611765565b63aba024f481186117655734612dbb57600e5460405260206040f3611765565b6370a08231811861055c57602436103417612dbb576004358060a01c612dbb5760405260116040516020525f5260405f205460605260206060f35b63b6b55f25811861176557602436103417612dbb57336101c05261096a56611765565b6318160ddd811861059b5734612dbb5760025460405260206040f35b63ef8b30f7811861176557602436103417612dbb5760206004356040526105c260a0611d3c565b60a0f3611765565b63dd62ed3e811861176557604436103417612dbb576004358060a01c612dbb576040526024358060a01c612dbb5760605260126040516020525f5260405f20806060516020525f5260405f2090505460805260206080f3611765565b6395d89b4181186106a45734612dbb5760208060805260036040527f434c50000000000000000000000000000000000000000000000000000000000060605260408160800181518152602082015160208201528051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b63ce96cb77811861176557602436103417612dbb576004358060a01c612dbb5760c052601160c0516020525f5260405f20546040526106e360e0611cd6565b60e0516020612e535f395f516370a082316101005230610120526020610100602461011c845afa610716573d5f5f3e3d5ffd5b60203d10612dbb5761010090505180828118828410021890509050610140526020610140f3611765565b63313ce56781186117655734612dbb57601260405260206040f3611765565b63a9059cbb811861176557604436103417612dbb576004358060a01c612dbb576040526011336020525f5260405f208054602435808203828111612dbb579050905081555060116040516020525f5260405f208054602435808201828110612dbb5790509050815550604051337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60243560605260206060a3600160605260206060f3611765565b63095ea7b3811861176557604436103417612dbb576004358060a01c612dbb576040526024356012336020525f5260405f20806040516020525f5260405f20905055604051337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560243560605260206060a3600160605260206060f3611765565b6301e1d11481186117655734612dbb57600154604052600354606052606051604051808201828110612dbb579050905060805260206080f3611765565b63c6e6f592811861176557602436103417612dbb5760206004356040526108ec60a0611d3c565b60a0f3611765565b63402d267d811861176557602436103417612dbb576004358060a01c612dbb576040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60605260206060f3611765565b636e553f6581186109d457604436103417612dbb576024358060a01c612dbb576101c0525b610972611d9c565b6101c05160405260043560605261098a610200611e01565b610200516101e0526101c051337fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7600435610200526101e051610220526040610200a360206101e0f35b63b3d7f6b9811861176557602436103417612dbb5760206004356040526109fb60c0611cd6565b60c0f3611765565b63c63d75b68118610a5057602436103417612dbb576004358060a01c612dbb576040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60605260206060f35b63c5ebeaec8118610a7457602436103417612dbb5733610340523361036052611189565b635ec8ede4811861176557602436103417612dbb576020612e935f395f513318612dbb57620f424060043511612dbb5760043560105500611765565b63a0712d688118610acf57602436103417612dbb57336101c052610b25565b62f714ce811861176557604436103417612dbb576024358060a01c612dbb57610320523361034052610d2856611765565b6394bf804d8118610baa57604436103417612dbb576024358060a01c612dbb576101c0525b610b2d611d9c565b600435604052610b3e610200611cd6565b610200516101e0526101c0516040526101e051606052610b5f610220611e01565b61022051610200526101c051337fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d76101e0516102205261020051610240526040610220a360206101e0f35b6314fa10e1811861176557604436103417612dbb576004358060a01c612dbb5761032052610bd6612440565b61032051604052602435606052610beb61271f565b00611765565b630a28a477811861176557602436103417612dbb57600435604052610c1660a0611d3c565b60a0516020612e535f395f516370a0823160c0523060e052602060c0602460dc845afa610c45573d5f5f3e3d5ffd5b60203d10612dbb5760c0905051604052610c60610100611d3c565b6101005180828118828410021890509050610120526020610120f3611765565b632e1a7d4d8118610ca457602436103417612dbb5733610320523361034052610d28565b638456cb5981186117655734612dbb576020612e935f395f513318612dbb576001600d55427f32fb7c9891bc4f963c7de9f1186d2a7755c7d6e9f4604dabe1d8bb3027c2f49e5f6040a200611765565b63b460af948118610db757606436103417612dbb576024358060a01c612dbb57610320526044358060a01c612dbb57610340525b610d30612440565b600435604052610d41610380611d3c565b6103805161036052610320516040526103405160605261036051608052610d696103a061249f565b6103a051610380526103405161032051337ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db6004356103a052610360516103c05260406103a0a46020610360f35b634cdad506811861176557602436103417612dbb57600435604052610ddc60c0611cd6565b60c0516020612e535f395f516370a0823160e0523061010052602060e0602460fc845afa610e0c573d5f5f3e3d5ffd5b60203d10612dbb5760e0905051604052610e27610120611d3c565b6101205180828118828410021890509050610140526020610140f3611765565b63d905777e811861176557602436103417612dbb576004358060a01c612dbb5760a052601160a0516020525f5260405f20546020612e535f395f516370a0823160c0523060e052602060c0602460dc845afa610ea5573d5f5f3e3d5ffd5b60203d10612dbb5760c0905051604052610ec0610100611d3c565b6101005180828118828410021890509050610120526020610120f3611765565b63db006a758118610f0457602436103417612dbb5733610320523361034052611080565b63b5effcf3811861176557604436103417612dbb576004358060a01c612dbb5761032052610f30612440565b61032051604052602435606052610f45612812565b336101c0526007546101e052610f5c610340612cd8565b61034051610fc9576017610360527f496e73756666696369656e7420436f6c6c61746572616c0000000000000000006103805261036050610360518061038001601f825f031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b00611765565b637bde82f28118610ffd57604436103417612dbb576024358060a01c612dbb57610320523361034052611080565b633f4ba83a81186117655734612dbb576020612e935f395f513318612dbb575f600d55427fb96cc4c95dd57612feeeaed56e65b2fd6ba67b101d0592527f05756fafcab4b45f6040a200611765565b63ba087652811861176557606436103417612dbb576024358060a01c612dbb57610320526044358060a01c612dbb57610340525b611088612440565b61032051604052610340516060526004356080526110a761038061249f565b61038051610360526103405161032051337ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db61036051610380526004356103a0526040610380a46020610360f3611765565b6332874ec7811861176557604436103417612dbb576004358060a01c612dbb576040526024358060a01c612dbb5760605260136040516020525f5260405f20806060516020525f5260405f2090505460805260206080f3611765565b63d516418481186112ac57606436103417612dbb576024358060a01c612dbb57610340526044358060a01c612dbb57610360525b611191611d9c565b611199612440565b3361034051146111d6576013610340516020525f5260405f2080336020525f5260405f2090508054600435808203828111612dbb57905090508155505b6004356101a052610340516101c052610360516101e0526111f86103a061297e565b6103a05161038052610340516101c0526007546101e05261121a6103a0612cd8565b6103a0516112875760176103c0527f496e73756666696369656e7420436f6c6c61746572616c0000000000000000006103e0526103c0506103c051806103e001601f825f031636823750506308c379a06103805260206103a052601f19601f6103c051011660440161039cfd5b600854604052600954606052600a546080525f60a0526112a5611f9f565b6020610380f35b631c12948e81186117655734612dbb576020612e935f395f516326cfa27c606052602060606004607c845afa6112e4573d5f5f3e3d5ffd5b60203d10612dbb576060518060a01c612dbb5760a05260a0905051604052600854606052600954608052600a5460a05260a05160c05260116040516020525f5260405f205460c051808201828110612dbb579050905060116040516020525f5260405f20555f600a556040515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60c05160e052602060e0a300611765565b63371fd8e6811861176557602436103417612dbb576113a0612440565b60206004356101e0526113b4610320612baa565b610320f3611765565b634914c008811861176557606436103417612dbb576004358060a01c612dbb57610320526044358060a01c612dbb5761034052604036610360376114026103a06128f7565b6103a08051610380526020810151610360525061141d612440565b6060366103a0376003546104005260045461042052610320516101c052610360516101e05261144d610440612cd8565b6104405161158d576006610320516020525f5260405f20546104605260243561046051808281188284100218905090506103e052610460516103e051808203828111612dbb57905090506006610320516020525f5260405f205561040051604052610420516060526103e0516080525f60a0526114cb6104806117fc565b610480516103c0526103c0516201b5808102816201b580820418612dbb57905061036051808202811583838304141715612dbb579050905069152d02c7e14af6800000810490506103a0526005610320516020525f5260405f20546103a05111611535575f611540565b610460516103e05118155b1561155a576005610320516020525f5260405f20546103a0525b6005610320516020525f5260405f20546103a051808203828111612dbb57905090506005610320516020525f5260405f20555b6103c0516115fa576018610440527f436f67506169723a205573657220697320736f6c76656e7400000000000000006104605261044050610440518061046001601f825f031636823750506308c379a061040052602061042052601f19601f61044051011660440161041cfd5b6003546103c0518060801c612dbb578082038060801c612dbb57905090506003556004546103e0518060801c612dbb578082038060801c612dbb57905090506004555f546103a051808203828111612dbb57905090505f556020612e735f395f5163a9059cbb6104405261034051610460526103a051610480526020610440604461045c5f855af161168e573d5f5f3e3d5ffd5b3d6116a557803b15612dbb5760016104a0526116be565b60203d10612dbb57610440518060011c612dbb576104a0525b6104a090505115612dbb576020612e535f395f516323b872dd61044052336104605230610480526103c0516104a0526020610440606461045c5f855af1611707573d5f5f3e3d5ffd5b3d61171e57803b15612dbb5760016104c052611737565b60203d10612dbb57610440518060011c612dbb576104c0525b6104c090505115612dbb576001546103c0518060801c612dbb578082018060801c612dbb5790509050600155005b5f5ffd5b60405161177f576080518152506117fa566117fa565b608051606051808202811583838304141715612dbb57905090506040518015612dbb578082049050905060a05260805160a051604051808202811583838304141715612dbb57905090506060518015612dbb578082049050905010156117f35760a05160018101818110612dbb57905060a0525b60a0518152505b565b6060516118125760805181525061189b5661189b565b608051604051808202811583838304141715612dbb57905090506060518015612dbb578082049050905060c05260a05161184c575f61187b565b60805160c051606051808202811583838304141715612dbb57905090506040518015612dbb5780820490509050105b156118945760c05160018101818110612dbb57905060c0525b60c0518152505b565b60c0516101205260e051610140526101205160405261014051606052610100516080526118cb610180611769565b610180516101605261012051610100518060801c612dbb578082018060801c612dbb57905090506101205261014051610160518060801c612dbb578082018060801c612dbb57905090506101405261012051815261014051602082015261016051604082015250565b60e0516101605261010051610180526101605160405261018051606052610120516080526101405160a05261196a6101c06117fc565b6101c0516101a052610160516101a0518060801c612dbb578082038060801c612dbb57905090506101605261018051610120518060801c612dbb578082038060801c612dbb5790509050610180526101605181526101805160208201526101a051604082015250565b608051611a3657601e60c0527f4d6174683a206d756c5f646976206469766973696f6e206279207a65726f000060e05260c05060c0518060e001601f825f031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b6040516060517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183099050905060c0526060516040510260e0525f6101005260e05160c05110611a915760e05160c0510361010052611aa0565b600160e05160c0510303610100525b61010051611afa5760a051611ab5575f611ad1565b6040516060516080518015612dbb578082840990509050905015155b611ae85760805160e05104815250611cd456611afa565b600160805160e0510401815250611cd4565b6101005160805111611b69576016610120527f4d6174683a206d756c5f646976206f766572666c6f77000000000000000000006101405261012050610120518061014001601f825f031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b6040516060516080518015612dbb57808284099050905090506101205260e051610120511115611b9f5760016101005103610100525b6101205160e0510360e0526080516080515f0316610140526101405160805104610160526101405160e0510460e052600161014051610140515f0304016101405261014051610100510260e0511760e05260026101605160030218610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805160e051026101a05260a051611c95575f611cb1565b6040516060516080518015612dbb578082840990509050905015155b15611ccc576101a05160018101818110612dbb5790506101a0525b6101a0518152505b565b600154606052600254608052608051611cf457604051815250611d3a565b6060516003548082018060801c612dbb579050905060a05260405160a051808202811583838304141715612dbb57905090506080518015612dbb57808204905090508152505b565b6002546060526001546003548082018060801c612dbb5790509050608052608051611d6c57604051815250611d9a565b604051606051808202811583838304141715612dbb57905090506080518015612dbb57808204905090508152505b565b600d5415611dff57600b6040527f506169722050617573656400000000000000000000000000000000000000000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b565b60015460805260025460a0526080516003548082018060801c612dbb579050905060c0525f60e05260c051611e3b5760605160e052611e69565b60605160a051808202811583838304141715612dbb579050905060c0518015612dbb578082049050905060e0525b6103e760a05160e0518060801c612dbb578082018060801c612dbb579050905013611e97575f815250611f9d565b6001546060518060801c612dbb578082018060801c612dbb57905090506101005260025460e0518060801c612dbb578082018060801c612dbb579050905061012052610100516001556101205160025560116040516020525f5260405f205460e051808201828110612dbb5790509050610100526101005160116040516020525f5260405f20556020612e535f395f516323b872dd6101205233610140523061016052606051610180526020610120606461013c5f855af1611f5b573d5f5f3e3d5ffd5b3d611f7257803b15612dbb5760016101a052611f8b565b60203d10612dbb57610120518060011c612dbb576101a0525b6101a090505115612dbb5760e0518152505b565b60405160c05260605160e05260805161010052428060401c612dbb5760e052600354610120526004546101405261014051612006576020612ef35f395f5160c05114611fee576020612ef360c0395b60c05160085560e05160095561010051600a5561243e565b604036610160376001546101a0526002546101c0526101205160c051808202811583838304141715612dbb579050905060a051808202811583838304141715612dbb5790509050670de0b6b3a7640000810490506101605261012051610160518060801c612dbb578082018060801c612dbb5790509050610120526101a05161012051808201828110612dbb57905090506101e05261016051600f54808202811583838304141715612dbb5790509050620f42408104905061020052610200516101c051808202811583838304141715612dbb57905090506101e0518015612dbb57808204905090506101805261010051610180518060801c612dbb578082018060801c612dbb5790509050610100526101c051610180518060801c612dbb578082018060801c612dbb5790509050600255610120516003556101405160045561012051670de0b6b3a7640000810281670de0b6b3a7640000820418612dbb5790506101e0518015612dbb5780820490509050610220526020612eb35f395f5161022051106122a7576020612ed35f395f516102205111156123a757610220516020612ed35f395f51808203828111612dbb5790509050670de0b6b3a7640000810281670de0b6b3a7640000820418612dbb5790506020612ed35f395f518015612dbb5780820490509050610240526020612f535f395f516102405161024051808202811583838304141715612dbb579050905060a051808202811583838304141715612dbb5790509050808201828110612dbb57905090506102605260c05161026051808202811583838304141715612dbb57905090506020612f535f395f518015612dbb57808204905090508060401c612dbb57610280526102805160c0526020612f335f395f516102805113156123a7576020612f3360c0396123a7565b6020612eb35f395f5161022051808203828111612dbb5790509050670de0b6b3a7640000810281670de0b6b3a7640000820418612dbb5790506020612eb35f395f518015612dbb5780820490509050610240526020612f535f395f516102405161024051808202811583838304141715612dbb579050905060a051808202811583838304141715612dbb5790509050808201828110612dbb57905090506102605260c0516020612f535f395f51808202811583838304141715612dbb5790509050610260518015612dbb57808204905090508060401c612dbb57610280526102805160c0526020612f135f395f5160c05112156123a7576020612f1360c0395b428060401c612dbb57600c548082038060401c612dbb5790509050610240526203f481610240511261242a57600b5460c051136123e957601054600f5561242a565b60c051600b548082038060401c612dbb5790509050610260526361830fc1610260511261242a57428060401c612dbb57600c5560c051600b55620f4240600f555b60c05160085560e05160095561010051600a555b565b6008546102a0526009546102c052600a546102e052426102c051808203828111612dbb579050905061030052610300516124795761249d565b6102a0516040526102c0516060526102e0516080526103005160a05261249d611f9f565b565b336060511461255b5760805160126060516020525f5260405f2080336020525f5260405f20905054101561252957601660a0527f496e73756666696369656e7420416c6c6f77616e63650000000000000000000060c05260a05060a0518060c001601f825f031636823750506308c379a06060526020608052601f19601f60a0510116604401607cfd5b60126060516020525f5260405f2080336020525f5260405f2090508054608051808203828111612dbb57905090508155505b60015460a05260025460c05260a0516003548082018060801c612dbb579050905060e05260805160e051808202811583838304141715612dbb579050905060c0518015612dbb57808204905090506101005260a051610100518060801c612dbb578082038060801c612dbb579050905060a05260c0516080518060801c612dbb578082038060801c612dbb579050905060c0526103e860c051121561265d57600d610120527f42656c6f77204d696e696d756d000000000000000000000000000000000000006101405261012050610120518061014001601f825f031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b60a05160015560c05160025560116060516020525f5260405f2054608051808203828111612dbb5790509050610120526101205160116060516020525f5260405f20556020612e535f395f5163a9059cbb610140526040516101605261010051610180526020610140604461015c5f855af16126db573d5f5f3e3d5ffd5b3d6126f257803b15612dbb5760016101a05261270b565b60203d10612dbb57610140518060011c612dbb576101a0525b6101a090505115612dbb5761010051815250565b60056040516020525f5260405f2054606051808201828110612dbb579050905060805260805160056040516020525f5260405f20555f5460a05260a051606051808201828110612dbb57905090505f556020612e735f395f516323b872dd60c0523360e052306101005260605161012052602060c0606460dc5f855af16127a8573d5f5f3e3d5ffd5b3d6127bf57803b15612dbb576001610140526127d7565b60203d10612dbb5760c0518060011c612dbb57610140525b61014090505115612dbb576080516060516040517fe3f4fa74d049cf7d64965afd6ce83c826cd313cec824ecfb9aacf36886090b495f60c0a4565b6005336020525f5260405f2054606051808203828111612dbb57905090506080526080516005336020525f5260405f20555f54606051808203828111612dbb57905090505f556020612e735f395f5163a9059cbb60a05260405160c05260605160e052602060a0604460bc5f855af161288d573d5f5f3e3d5ffd5b3d6128a457803b15612dbb576001610100526128bc565b60203d10612dbb5760a0518060011c612dbb57610100525b61010090505115612dbb576080516060516040517fdec5d726a70bdc7ab7e167507e34e068ab89db504d9ddcb08618c73a1f10a93e5f60a0a4565b6040366040376020612e335f395f51636d4ce63c608052604060806004609c5f855af1612926573d5f5f3e3d5ffd5b60403d10612dbb576080518060011c612dbb5760e05260a0516101005260e0905080516040526020810151606052506040516129675760075460605261296e565b6060516007555b6040518152606051602082015250565b6129896102006128f7565b610200506101a051600e54808202811583838304141715612dbb5790509050620186a081049050610200526060366102203760035460c05260045460e0526101a05161020051808201828110612dbb5790509050610100526129ec61028061189d565b61028080516102205260208101516102405260408101516102605250610220516003556102405160045560066101c0516020525f5260405f205461026051808201828110612dbb579050905060066101c0516020525f5260405f2055600154610280526002546102a0526103e86102a0511215612ac857600d6102c0527f42656c6f77204d696e696d756d000000000000000000000000000000000000006102e0526102c0506102c051806102e001601f825f031636823750506308c379a06102805260206102a052601f19601f6102c051011660440161029cfd5b610280516101a051808203828111612dbb57905090508060801c612dbb5761028052610280516001556102a0516002556020612e535f395f5163a9059cbb6102c0526101e0516102e0526101a0516103005260206102c060446102dc5f855af1612b34573d5f5f3e3d5ffd5b3d612b4b57803b15612dbb57600161032052612b64565b60203d10612dbb576102c0518060011c612dbb57610320525b61032090505115612dbb576101c0516101e0516101a0517f322a69e46c4e1be12df82297341b3c5651c9f47519342541b412514bed8aac895f6102c0a46101a051815250565b6060366102003760035460e052600454610100526101e05161012052600161014052612bd7610260611934565b6102608051610200526020810151610220526040810151610240525061020051600355610220516004556006336020525f5260405f20546101e051808203828111612dbb57905090506006336020525f5260405f2055600154610260526020612e535f395f516323b872dd61028052336102a052306102c052610240516102e0526020610280606461029c5f855af1612c72573d5f5f3e3d5ffd5b3d612c8957803b15612dbb57600161030052612ca2565b60203d10612dbb57610280518060011c612dbb57610300525b61030090505115612dbb5761026051610240518060801c612dbb578082018060801c612dbb579050905060015561024051815250565b60066101c0516020525f5260405f20546102005261020051612cfe576001815250612db9565b60056101c0516020525f5260405f20546102205261022051612d23575f815250612db9565b6003546102405260045461026052610220516509184e72a0008102816509184e72a000820418612dbb57905062014c0881028162014c08820418612dbb579050610280526102005161024051808202811583838304141715612dbb57905090506040526101e051606052610260516080525f60a052612da36102a06119d3565b6102a05161020052610200516102805110158152505b565b5f80fd17651765050101b40fcf018e11550c8017650b00138317651765052103bc04bf1765074008c51765030001da13bd0ee00cf404991765176517651765176500931765176505ca0bf10a0310f9088817651765075f04260626014d04e10ab00807104c08f4176509450e47003a0018057f1765176584192e33811874190140a16576797065728300030a001700000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a40000000000000000000000005300000000000000000000000000000000000004000000000000000000000000c24c50eb63736befb59d55d18d998d088d22ec3700000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000058d15e176280000000000000000000000000000000000000000000000000000000000005e80a6c00000000000000000000000000000000000000000000000000000000025cd0f800000000000000000000000000000000000000000000000000000000295848f4000000000000000000000000000000054a2b63d65d79d094abb66880000000000

Deployed Bytecode

0x5f3560e01c6002603a820660011b612dbf01601e395f51565b637dc0d1d081186117655734612dbb576020612e3360403960206040f3611765565b6338d52e0f81186100585734612dbb576020612e5360403960206040f35b63dba2d553811861176557602436103417612dbb576020612e935f395f513318612dbb5761c35060043511612dbb57600435600e5500611765565b63d8dfeb4581186100b15734612dbb576020612e7360403960206040f35b6306fdde03811861012f5734612dbb5760208060805260116040527f436f6720506f6f6c204c5020546f6b656e00000000000000000000000000000060605260408160800181518152602082015160208201528051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b63f8ba4cff81186117655734612dbb57610147612440565b00611765565b631ac0e29281186101685734612dbb575f5460405260206040f35b63fe9f6e2481186117655734612dbb5760406101856101206128f7565b610120f3611765565b636b8833c981186117655734612dbb5760015460405260025460605260406040f3611765565b638274109781186117655734612dbb5760035460405260045460605260406040f3611765565b632b5fca1d811861021557602436103417612dbb576004358060a01c612dbb5760405260056040516020525f5260405f205460605260206060f35b6323b872dd811861176557606436103417612dbb576004358060a01c612dbb576040526024358060a01c612dbb5760605260126040516020525f5260405f2080336020525f5260405f2090508054604435808203828111612dbb579050905081555060116040516020525f5260405f208054604435808203828111612dbb579050905081555060116060516020525f5260405f208054604435808201828110612dbb57905090508155506060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60443560805260206080a3600160805260206080f3611765565b6377917072811861033b57602436103417612dbb576004358060a01c612dbb5760405260066040516020525f5260405f205460605260206060f35b634c01b790811861176557604436103417612dbb576004358060a01c612dbb576040526024356013336020525f5260405f20806040516020525f5260405f20905055604051337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560243560605260206060a3600160605260206060f3611765565b63171ef0b281186103d85734612dbb5760075460405260206040f35b63648c587481186103f45734612dbb5760105460405260206040f35b634b3fd148811861176557604436103417612dbb576024358060a01c612dbb5761034052336103605261118956611765565b633f0bc5bc811861044e5734612dbb57600854604052600954606052600a5460805260606040f35b6316552732811861046a5734612dbb57600f5460405260206040f35b6307a2d13a811861176557602436103417612dbb57602060043560405261049160c0611cd6565b60c0f3611765565b6363eded9581186117655734612dbb57600b54604052600c5460605260406040f3611765565b63c45a015581186117655734612dbb576020612e9360403960206040f3611765565b635c975abb81186117655734612dbb57600d5460405260206040f3611765565b63aba024f481186117655734612dbb57600e5460405260206040f3611765565b6370a08231811861055c57602436103417612dbb576004358060a01c612dbb5760405260116040516020525f5260405f205460605260206060f35b63b6b55f25811861176557602436103417612dbb57336101c05261096a56611765565b6318160ddd811861059b5734612dbb5760025460405260206040f35b63ef8b30f7811861176557602436103417612dbb5760206004356040526105c260a0611d3c565b60a0f3611765565b63dd62ed3e811861176557604436103417612dbb576004358060a01c612dbb576040526024358060a01c612dbb5760605260126040516020525f5260405f20806060516020525f5260405f2090505460805260206080f3611765565b6395d89b4181186106a45734612dbb5760208060805260036040527f434c50000000000000000000000000000000000000000000000000000000000060605260408160800181518152602082015160208201528051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b63ce96cb77811861176557602436103417612dbb576004358060a01c612dbb5760c052601160c0516020525f5260405f20546040526106e360e0611cd6565b60e0516020612e535f395f516370a082316101005230610120526020610100602461011c845afa610716573d5f5f3e3d5ffd5b60203d10612dbb5761010090505180828118828410021890509050610140526020610140f3611765565b63313ce56781186117655734612dbb57601260405260206040f3611765565b63a9059cbb811861176557604436103417612dbb576004358060a01c612dbb576040526011336020525f5260405f208054602435808203828111612dbb579050905081555060116040516020525f5260405f208054602435808201828110612dbb5790509050815550604051337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60243560605260206060a3600160605260206060f3611765565b63095ea7b3811861176557604436103417612dbb576004358060a01c612dbb576040526024356012336020525f5260405f20806040516020525f5260405f20905055604051337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560243560605260206060a3600160605260206060f3611765565b6301e1d11481186117655734612dbb57600154604052600354606052606051604051808201828110612dbb579050905060805260206080f3611765565b63c6e6f592811861176557602436103417612dbb5760206004356040526108ec60a0611d3c565b60a0f3611765565b63402d267d811861176557602436103417612dbb576004358060a01c612dbb576040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60605260206060f3611765565b636e553f6581186109d457604436103417612dbb576024358060a01c612dbb576101c0525b610972611d9c565b6101c05160405260043560605261098a610200611e01565b610200516101e0526101c051337fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7600435610200526101e051610220526040610200a360206101e0f35b63b3d7f6b9811861176557602436103417612dbb5760206004356040526109fb60c0611cd6565b60c0f3611765565b63c63d75b68118610a5057602436103417612dbb576004358060a01c612dbb576040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60605260206060f35b63c5ebeaec8118610a7457602436103417612dbb5733610340523361036052611189565b635ec8ede4811861176557602436103417612dbb576020612e935f395f513318612dbb57620f424060043511612dbb5760043560105500611765565b63a0712d688118610acf57602436103417612dbb57336101c052610b25565b62f714ce811861176557604436103417612dbb576024358060a01c612dbb57610320523361034052610d2856611765565b6394bf804d8118610baa57604436103417612dbb576024358060a01c612dbb576101c0525b610b2d611d9c565b600435604052610b3e610200611cd6565b610200516101e0526101c0516040526101e051606052610b5f610220611e01565b61022051610200526101c051337fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d76101e0516102205261020051610240526040610220a360206101e0f35b6314fa10e1811861176557604436103417612dbb576004358060a01c612dbb5761032052610bd6612440565b61032051604052602435606052610beb61271f565b00611765565b630a28a477811861176557602436103417612dbb57600435604052610c1660a0611d3c565b60a0516020612e535f395f516370a0823160c0523060e052602060c0602460dc845afa610c45573d5f5f3e3d5ffd5b60203d10612dbb5760c0905051604052610c60610100611d3c565b6101005180828118828410021890509050610120526020610120f3611765565b632e1a7d4d8118610ca457602436103417612dbb5733610320523361034052610d28565b638456cb5981186117655734612dbb576020612e935f395f513318612dbb576001600d55427f32fb7c9891bc4f963c7de9f1186d2a7755c7d6e9f4604dabe1d8bb3027c2f49e5f6040a200611765565b63b460af948118610db757606436103417612dbb576024358060a01c612dbb57610320526044358060a01c612dbb57610340525b610d30612440565b600435604052610d41610380611d3c565b6103805161036052610320516040526103405160605261036051608052610d696103a061249f565b6103a051610380526103405161032051337ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db6004356103a052610360516103c05260406103a0a46020610360f35b634cdad506811861176557602436103417612dbb57600435604052610ddc60c0611cd6565b60c0516020612e535f395f516370a0823160e0523061010052602060e0602460fc845afa610e0c573d5f5f3e3d5ffd5b60203d10612dbb5760e0905051604052610e27610120611d3c565b6101205180828118828410021890509050610140526020610140f3611765565b63d905777e811861176557602436103417612dbb576004358060a01c612dbb5760a052601160a0516020525f5260405f20546020612e535f395f516370a0823160c0523060e052602060c0602460dc845afa610ea5573d5f5f3e3d5ffd5b60203d10612dbb5760c0905051604052610ec0610100611d3c565b6101005180828118828410021890509050610120526020610120f3611765565b63db006a758118610f0457602436103417612dbb5733610320523361034052611080565b63b5effcf3811861176557604436103417612dbb576004358060a01c612dbb5761032052610f30612440565b61032051604052602435606052610f45612812565b336101c0526007546101e052610f5c610340612cd8565b61034051610fc9576017610360527f496e73756666696369656e7420436f6c6c61746572616c0000000000000000006103805261036050610360518061038001601f825f031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b00611765565b637bde82f28118610ffd57604436103417612dbb576024358060a01c612dbb57610320523361034052611080565b633f4ba83a81186117655734612dbb576020612e935f395f513318612dbb575f600d55427fb96cc4c95dd57612feeeaed56e65b2fd6ba67b101d0592527f05756fafcab4b45f6040a200611765565b63ba087652811861176557606436103417612dbb576024358060a01c612dbb57610320526044358060a01c612dbb57610340525b611088612440565b61032051604052610340516060526004356080526110a761038061249f565b61038051610360526103405161032051337ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db61036051610380526004356103a0526040610380a46020610360f3611765565b6332874ec7811861176557604436103417612dbb576004358060a01c612dbb576040526024358060a01c612dbb5760605260136040516020525f5260405f20806060516020525f5260405f2090505460805260206080f3611765565b63d516418481186112ac57606436103417612dbb576024358060a01c612dbb57610340526044358060a01c612dbb57610360525b611191611d9c565b611199612440565b3361034051146111d6576013610340516020525f5260405f2080336020525f5260405f2090508054600435808203828111612dbb57905090508155505b6004356101a052610340516101c052610360516101e0526111f86103a061297e565b6103a05161038052610340516101c0526007546101e05261121a6103a0612cd8565b6103a0516112875760176103c0527f496e73756666696369656e7420436f6c6c61746572616c0000000000000000006103e0526103c0506103c051806103e001601f825f031636823750506308c379a06103805260206103a052601f19601f6103c051011660440161039cfd5b600854604052600954606052600a546080525f60a0526112a5611f9f565b6020610380f35b631c12948e81186117655734612dbb576020612e935f395f516326cfa27c606052602060606004607c845afa6112e4573d5f5f3e3d5ffd5b60203d10612dbb576060518060a01c612dbb5760a05260a0905051604052600854606052600954608052600a5460a05260a05160c05260116040516020525f5260405f205460c051808201828110612dbb579050905060116040516020525f5260405f20555f600a556040515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60c05160e052602060e0a300611765565b63371fd8e6811861176557602436103417612dbb576113a0612440565b60206004356101e0526113b4610320612baa565b610320f3611765565b634914c008811861176557606436103417612dbb576004358060a01c612dbb57610320526044358060a01c612dbb5761034052604036610360376114026103a06128f7565b6103a08051610380526020810151610360525061141d612440565b6060366103a0376003546104005260045461042052610320516101c052610360516101e05261144d610440612cd8565b6104405161158d576006610320516020525f5260405f20546104605260243561046051808281188284100218905090506103e052610460516103e051808203828111612dbb57905090506006610320516020525f5260405f205561040051604052610420516060526103e0516080525f60a0526114cb6104806117fc565b610480516103c0526103c0516201b5808102816201b580820418612dbb57905061036051808202811583838304141715612dbb579050905069152d02c7e14af6800000810490506103a0526005610320516020525f5260405f20546103a05111611535575f611540565b610460516103e05118155b1561155a576005610320516020525f5260405f20546103a0525b6005610320516020525f5260405f20546103a051808203828111612dbb57905090506005610320516020525f5260405f20555b6103c0516115fa576018610440527f436f67506169723a205573657220697320736f6c76656e7400000000000000006104605261044050610440518061046001601f825f031636823750506308c379a061040052602061042052601f19601f61044051011660440161041cfd5b6003546103c0518060801c612dbb578082038060801c612dbb57905090506003556004546103e0518060801c612dbb578082038060801c612dbb57905090506004555f546103a051808203828111612dbb57905090505f556020612e735f395f5163a9059cbb6104405261034051610460526103a051610480526020610440604461045c5f855af161168e573d5f5f3e3d5ffd5b3d6116a557803b15612dbb5760016104a0526116be565b60203d10612dbb57610440518060011c612dbb576104a0525b6104a090505115612dbb576020612e535f395f516323b872dd61044052336104605230610480526103c0516104a0526020610440606461045c5f855af1611707573d5f5f3e3d5ffd5b3d61171e57803b15612dbb5760016104c052611737565b60203d10612dbb57610440518060011c612dbb576104c0525b6104c090505115612dbb576001546103c0518060801c612dbb578082018060801c612dbb5790509050600155005b5f5ffd5b60405161177f576080518152506117fa566117fa565b608051606051808202811583838304141715612dbb57905090506040518015612dbb578082049050905060a05260805160a051604051808202811583838304141715612dbb57905090506060518015612dbb578082049050905010156117f35760a05160018101818110612dbb57905060a0525b60a0518152505b565b6060516118125760805181525061189b5661189b565b608051604051808202811583838304141715612dbb57905090506060518015612dbb578082049050905060c05260a05161184c575f61187b565b60805160c051606051808202811583838304141715612dbb57905090506040518015612dbb5780820490509050105b156118945760c05160018101818110612dbb57905060c0525b60c0518152505b565b60c0516101205260e051610140526101205160405261014051606052610100516080526118cb610180611769565b610180516101605261012051610100518060801c612dbb578082018060801c612dbb57905090506101205261014051610160518060801c612dbb578082018060801c612dbb57905090506101405261012051815261014051602082015261016051604082015250565b60e0516101605261010051610180526101605160405261018051606052610120516080526101405160a05261196a6101c06117fc565b6101c0516101a052610160516101a0518060801c612dbb578082038060801c612dbb57905090506101605261018051610120518060801c612dbb578082038060801c612dbb5790509050610180526101605181526101805160208201526101a051604082015250565b608051611a3657601e60c0527f4d6174683a206d756c5f646976206469766973696f6e206279207a65726f000060e05260c05060c0518060e001601f825f031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b6040516060517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183099050905060c0526060516040510260e0525f6101005260e05160c05110611a915760e05160c0510361010052611aa0565b600160e05160c0510303610100525b61010051611afa5760a051611ab5575f611ad1565b6040516060516080518015612dbb578082840990509050905015155b611ae85760805160e05104815250611cd456611afa565b600160805160e0510401815250611cd4565b6101005160805111611b69576016610120527f4d6174683a206d756c5f646976206f766572666c6f77000000000000000000006101405261012050610120518061014001601f825f031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b6040516060516080518015612dbb57808284099050905090506101205260e051610120511115611b9f5760016101005103610100525b6101205160e0510360e0526080516080515f0316610140526101405160805104610160526101405160e0510460e052600161014051610140515f0304016101405261014051610100510260e0511760e05260026101605160030218610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805160e051026101a05260a051611c95575f611cb1565b6040516060516080518015612dbb578082840990509050905015155b15611ccc576101a05160018101818110612dbb5790506101a0525b6101a0518152505b565b600154606052600254608052608051611cf457604051815250611d3a565b6060516003548082018060801c612dbb579050905060a05260405160a051808202811583838304141715612dbb57905090506080518015612dbb57808204905090508152505b565b6002546060526001546003548082018060801c612dbb5790509050608052608051611d6c57604051815250611d9a565b604051606051808202811583838304141715612dbb57905090506080518015612dbb57808204905090508152505b565b600d5415611dff57600b6040527f506169722050617573656400000000000000000000000000000000000000000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b565b60015460805260025460a0526080516003548082018060801c612dbb579050905060c0525f60e05260c051611e3b5760605160e052611e69565b60605160a051808202811583838304141715612dbb579050905060c0518015612dbb578082049050905060e0525b6103e760a05160e0518060801c612dbb578082018060801c612dbb579050905013611e97575f815250611f9d565b6001546060518060801c612dbb578082018060801c612dbb57905090506101005260025460e0518060801c612dbb578082018060801c612dbb579050905061012052610100516001556101205160025560116040516020525f5260405f205460e051808201828110612dbb5790509050610100526101005160116040516020525f5260405f20556020612e535f395f516323b872dd6101205233610140523061016052606051610180526020610120606461013c5f855af1611f5b573d5f5f3e3d5ffd5b3d611f7257803b15612dbb5760016101a052611f8b565b60203d10612dbb57610120518060011c612dbb576101a0525b6101a090505115612dbb5760e0518152505b565b60405160c05260605160e05260805161010052428060401c612dbb5760e052600354610120526004546101405261014051612006576020612ef35f395f5160c05114611fee576020612ef360c0395b60c05160085560e05160095561010051600a5561243e565b604036610160376001546101a0526002546101c0526101205160c051808202811583838304141715612dbb579050905060a051808202811583838304141715612dbb5790509050670de0b6b3a7640000810490506101605261012051610160518060801c612dbb578082018060801c612dbb5790509050610120526101a05161012051808201828110612dbb57905090506101e05261016051600f54808202811583838304141715612dbb5790509050620f42408104905061020052610200516101c051808202811583838304141715612dbb57905090506101e0518015612dbb57808204905090506101805261010051610180518060801c612dbb578082018060801c612dbb5790509050610100526101c051610180518060801c612dbb578082018060801c612dbb5790509050600255610120516003556101405160045561012051670de0b6b3a7640000810281670de0b6b3a7640000820418612dbb5790506101e0518015612dbb5780820490509050610220526020612eb35f395f5161022051106122a7576020612ed35f395f516102205111156123a757610220516020612ed35f395f51808203828111612dbb5790509050670de0b6b3a7640000810281670de0b6b3a7640000820418612dbb5790506020612ed35f395f518015612dbb5780820490509050610240526020612f535f395f516102405161024051808202811583838304141715612dbb579050905060a051808202811583838304141715612dbb5790509050808201828110612dbb57905090506102605260c05161026051808202811583838304141715612dbb57905090506020612f535f395f518015612dbb57808204905090508060401c612dbb57610280526102805160c0526020612f335f395f516102805113156123a7576020612f3360c0396123a7565b6020612eb35f395f5161022051808203828111612dbb5790509050670de0b6b3a7640000810281670de0b6b3a7640000820418612dbb5790506020612eb35f395f518015612dbb5780820490509050610240526020612f535f395f516102405161024051808202811583838304141715612dbb579050905060a051808202811583838304141715612dbb5790509050808201828110612dbb57905090506102605260c0516020612f535f395f51808202811583838304141715612dbb5790509050610260518015612dbb57808204905090508060401c612dbb57610280526102805160c0526020612f135f395f5160c05112156123a7576020612f1360c0395b428060401c612dbb57600c548082038060401c612dbb5790509050610240526203f481610240511261242a57600b5460c051136123e957601054600f5561242a565b60c051600b548082038060401c612dbb5790509050610260526361830fc1610260511261242a57428060401c612dbb57600c5560c051600b55620f4240600f555b60c05160085560e05160095561010051600a555b565b6008546102a0526009546102c052600a546102e052426102c051808203828111612dbb579050905061030052610300516124795761249d565b6102a0516040526102c0516060526102e0516080526103005160a05261249d611f9f565b565b336060511461255b5760805160126060516020525f5260405f2080336020525f5260405f20905054101561252957601660a0527f496e73756666696369656e7420416c6c6f77616e63650000000000000000000060c05260a05060a0518060c001601f825f031636823750506308c379a06060526020608052601f19601f60a0510116604401607cfd5b60126060516020525f5260405f2080336020525f5260405f2090508054608051808203828111612dbb57905090508155505b60015460a05260025460c05260a0516003548082018060801c612dbb579050905060e05260805160e051808202811583838304141715612dbb579050905060c0518015612dbb57808204905090506101005260a051610100518060801c612dbb578082038060801c612dbb579050905060a05260c0516080518060801c612dbb578082038060801c612dbb579050905060c0526103e860c051121561265d57600d610120527f42656c6f77204d696e696d756d000000000000000000000000000000000000006101405261012050610120518061014001601f825f031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b60a05160015560c05160025560116060516020525f5260405f2054608051808203828111612dbb5790509050610120526101205160116060516020525f5260405f20556020612e535f395f5163a9059cbb610140526040516101605261010051610180526020610140604461015c5f855af16126db573d5f5f3e3d5ffd5b3d6126f257803b15612dbb5760016101a05261270b565b60203d10612dbb57610140518060011c612dbb576101a0525b6101a090505115612dbb5761010051815250565b60056040516020525f5260405f2054606051808201828110612dbb579050905060805260805160056040516020525f5260405f20555f5460a05260a051606051808201828110612dbb57905090505f556020612e735f395f516323b872dd60c0523360e052306101005260605161012052602060c0606460dc5f855af16127a8573d5f5f3e3d5ffd5b3d6127bf57803b15612dbb576001610140526127d7565b60203d10612dbb5760c0518060011c612dbb57610140525b61014090505115612dbb576080516060516040517fe3f4fa74d049cf7d64965afd6ce83c826cd313cec824ecfb9aacf36886090b495f60c0a4565b6005336020525f5260405f2054606051808203828111612dbb57905090506080526080516005336020525f5260405f20555f54606051808203828111612dbb57905090505f556020612e735f395f5163a9059cbb60a05260405160c05260605160e052602060a0604460bc5f855af161288d573d5f5f3e3d5ffd5b3d6128a457803b15612dbb576001610100526128bc565b60203d10612dbb5760a0518060011c612dbb57610100525b61010090505115612dbb576080516060516040517fdec5d726a70bdc7ab7e167507e34e068ab89db504d9ddcb08618c73a1f10a93e5f60a0a4565b6040366040376020612e335f395f51636d4ce63c608052604060806004609c5f855af1612926573d5f5f3e3d5ffd5b60403d10612dbb576080518060011c612dbb5760e05260a0516101005260e0905080516040526020810151606052506040516129675760075460605261296e565b6060516007555b6040518152606051602082015250565b6129896102006128f7565b610200506101a051600e54808202811583838304141715612dbb5790509050620186a081049050610200526060366102203760035460c05260045460e0526101a05161020051808201828110612dbb5790509050610100526129ec61028061189d565b61028080516102205260208101516102405260408101516102605250610220516003556102405160045560066101c0516020525f5260405f205461026051808201828110612dbb579050905060066101c0516020525f5260405f2055600154610280526002546102a0526103e86102a0511215612ac857600d6102c0527f42656c6f77204d696e696d756d000000000000000000000000000000000000006102e0526102c0506102c051806102e001601f825f031636823750506308c379a06102805260206102a052601f19601f6102c051011660440161029cfd5b610280516101a051808203828111612dbb57905090508060801c612dbb5761028052610280516001556102a0516002556020612e535f395f5163a9059cbb6102c0526101e0516102e0526101a0516103005260206102c060446102dc5f855af1612b34573d5f5f3e3d5ffd5b3d612b4b57803b15612dbb57600161032052612b64565b60203d10612dbb576102c0518060011c612dbb57610320525b61032090505115612dbb576101c0516101e0516101a0517f322a69e46c4e1be12df82297341b3c5651c9f47519342541b412514bed8aac895f6102c0a46101a051815250565b6060366102003760035460e052600454610100526101e05161012052600161014052612bd7610260611934565b6102608051610200526020810151610220526040810151610240525061020051600355610220516004556006336020525f5260405f20546101e051808203828111612dbb57905090506006336020525f5260405f2055600154610260526020612e535f395f516323b872dd61028052336102a052306102c052610240516102e0526020610280606461029c5f855af1612c72573d5f5f3e3d5ffd5b3d612c8957803b15612dbb57600161030052612ca2565b60203d10612dbb57610280518060011c612dbb57610300525b61030090505115612dbb5761026051610240518060801c612dbb578082018060801c612dbb579050905060015561024051815250565b60066101c0516020525f5260405f20546102005261020051612cfe576001815250612db9565b60056101c0516020525f5260405f20546102205261022051612d23575f815250612db9565b6003546102405260045461026052610220516509184e72a0008102816509184e72a000820418612dbb57905062014c0881028162014c08820418612dbb579050610280526102005161024051808202811583838304141715612dbb57905090506040526101e051606052610260516080525f60a052612da36102a06119d3565b6102a05161020052610200516102805110158152505b565b5f80fd17651765050101b40fcf018e11550c8017650b00138317651765052103bc04bf1765074008c51765030001da13bd0ee00cf404991765176517651765176500931765176505ca0bf10a0310f9088817651765075f04260626014d04e10ab00807104c08f4176509450e47003a0018057f17651765000000000000000000000000c24c50eb63736befb59d55d18d998d088d22ec3700000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a40000000000000000000000005300000000000000000000000000000000000004000000000000000000000000cd44fecb08bb28405992358131fd5081a0f550d000000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000058d15e176280000000000000000000000000000000000000000000000000000000000005e80a6c00000000000000000000000000000000000000000000000000000000025cd0f800000000000000000000000000000000000000000000000000000000295848f4000000000000000000000000000000054a2b63d65d79d094abb66880000000000

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

00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a40000000000000000000000005300000000000000000000000000000000000004000000000000000000000000c24c50eb63736befb59d55d18d998d088d22ec3700000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000058d15e176280000000000000000000000000000000000000000000000000000000000005e80a6c00000000000000000000000000000000000000000000000000000000025cd0f800000000000000000000000000000000000000000000000000000000295848f4000000000000000000000000000000054a2b63d65d79d094abb66880000000000

-----Decoded View---------------
Arg [0] : _asset (address): 0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4
Arg [1] : _collateral (address): 0x5300000000000000000000000000000000000004
Arg [2] : _oracle (address): 0xc24c50EB63736BefB59D55d18d998D088d22eC37
Arg [3] : min_target_utilization (uint256): 200000000000000000
Arg [4] : max_target_utilization (uint256): 400000000000000000
Arg [5] : starting_interest_per_second (uint64): 1585489600
Arg [6] : min_interest (uint64): 634195840
Arg [7] : max_interest (uint64): 11098427200
Arg [8] : elasticity (uint256): 28800000000000000000000000000000000000000

-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a4
Arg [1] : 0000000000000000000000005300000000000000000000000000000000000004
Arg [2] : 000000000000000000000000c24c50eb63736befb59d55d18d998d088d22ec37
Arg [3] : 00000000000000000000000000000000000000000000000002c68af0bb140000
Arg [4] : 000000000000000000000000000000000000000000000000058d15e176280000
Arg [5] : 000000000000000000000000000000000000000000000000000000005e80a6c0
Arg [6] : 0000000000000000000000000000000000000000000000000000000025cd0f80
Arg [7] : 0000000000000000000000000000000000000000000000000000000295848f40
Arg [8] : 00000000000000000000000000000054a2b63d65d79d094abb66880000000000


Block Transaction Gas Used Reward
view all blocks sequenced

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
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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