ETH Price: $3,883.85 (-2.89%)

Contract

0x1337F001E280420EcCe9E7B934Fa07D67fdb62CD

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Adjust_loan1290506012024-12-08 23:19:3914 hrs ago1733699979IN
Defi Money: CDP Main Controller
0 ETH0.0000007525610.001001
Create_loan1290461722024-12-08 20:52:0116 hrs ago1733691121IN
Defi Money: CDP Main Controller
0 ETH0.0000002194290.00010921
Close_loan1290292852024-12-08 11:29:0726 hrs ago1733657347IN
Defi Money: CDP Main Controller
0 ETH0.0000006037380.0010049
Create_loan1290237442024-12-08 8:24:2529 hrs ago1733646265IN
Defi Money: CDP Main Controller
0 ETH0.0000009775080.0010029
Set Delegate App...1289959382024-12-07 16:57:3344 hrs ago1733590653IN
Defi Money: CDP Main Controller
0 ETH0.0000004994230.00010059
Adjust_loan1289894152024-12-07 13:20:072 days ago1733577607IN
Defi Money: CDP Main Controller
0 ETH0.0000016888320.00100064
Close_loan1289813442024-12-07 8:51:052 days ago1733561465IN
Defi Money: CDP Main Controller
0 ETH0.0000024288130.0010004
Close_loan1289580352024-12-06 19:54:072 days ago1733514847IN
Defi Money: CDP Main Controller
0 ETH0.0000020366960.0010008
Close_loan1289580122024-12-06 19:53:212 days ago1733514801IN
Defi Money: CDP Main Controller
0 ETH0.0000017989260.0010008
Close_loan1289521632024-12-06 16:38:232 days ago1733503103IN
Defi Money: CDP Main Controller
0 ETH0.0000030928530.00010037
Adjust_loan1289505972024-12-06 15:46:112 days ago1733499971IN
Defi Money: CDP Main Controller
0 ETH0.0000047327330.00010046
Create_loan1289398642024-12-06 9:48:253 days ago1733478505IN
Defi Money: CDP Main Controller
0 ETH0.0000023940990.00120039
Adjust_loan1289386742024-12-06 9:08:453 days ago1733476125IN
Defi Money: CDP Main Controller
0 ETH0.0000016239680.00100053
Create_loan1289370312024-12-06 8:13:593 days ago1733472839IN
Defi Money: CDP Main Controller
0 ETH0.0000026751770.0010006
Adjust_loan1289244722024-12-06 1:15:213 days ago1733447721IN
Defi Money: CDP Main Controller
0 ETH0.0000007527040.00010066
Create_loan1289239752024-12-06 0:58:473 days ago1733446727IN
Defi Money: CDP Main Controller
0 ETH0.0000017006760.0010008
Adjust_loan1289151772024-12-05 20:05:313 days ago1733429131IN
Defi Money: CDP Main Controller
0 ETH0.0000006168640.00010097
Adjust_loan1289150572024-12-05 20:01:313 days ago1733428891IN
Defi Money: CDP Main Controller
0 ETH0.0000005958440.00010085
Close_loan1289045542024-12-05 14:11:253 days ago1733407885IN
Defi Money: CDP Main Controller
0 ETH0.0000021082220.0010005
Close_loan1288901472024-12-05 6:11:114 days ago1733379071IN
Defi Money: CDP Main Controller
0 ETH0.0000025279120.00100038
Create_loan1288777902024-12-04 23:19:174 days ago1733354357IN
Defi Money: CDP Main Controller
0 ETH0.0000025462270.00010039
Close_loan1288777622024-12-04 23:18:214 days ago1733354301IN
Defi Money: CDP Main Controller
0 ETH0.0000016579640.00010039
Adjust_loan1288665822024-12-04 17:05:414 days ago1733331941IN
Defi Money: CDP Main Controller
0 ETH0.0000006195010.00010422
Adjust_loan1288652942024-12-04 16:22:454 days ago1733329365IN
Defi Money: CDP Main Controller
0 ETH0.0000016335260.00100249
Adjust_loan1288618312024-12-04 14:27:194 days ago1733322439IN
Defi Money: CDP Main Controller
0 ETH0.0000016165440.00100061
View all transactions

Latest 11 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
1264497512024-10-09 18:24:3960 days ago1728498279
Defi Money: CDP Main Controller
 Contract Creation0 ETH
1264497512024-10-09 18:24:3960 days ago1728498279
Defi Money: CDP Main Controller
 Contract Creation0 ETH
1251753832024-09-10 6:25:4390 days ago1725949543
Defi Money: CDP Main Controller
 Contract Creation0 ETH
1251753832024-09-10 6:25:4390 days ago1725949543
Defi Money: CDP Main Controller
 Contract Creation0 ETH
1218763362024-06-25 21:37:29166 days ago1719351449
Defi Money: CDP Main Controller
 Contract Creation0 ETH
1218763362024-06-25 21:37:29166 days ago1719351449
Defi Money: CDP Main Controller
 Contract Creation0 ETH
1218763192024-06-25 21:36:55166 days ago1719351415
Defi Money: CDP Main Controller
 Contract Creation0 ETH
1218763192024-06-25 21:36:55166 days ago1719351415
Defi Money: CDP Main Controller
 Contract Creation0 ETH
1218762982024-06-25 21:36:13166 days ago1719351373
Defi Money: CDP Main Controller
 Contract Creation0 ETH
1218762982024-06-25 21:36:13166 days ago1719351373
Defi Money: CDP Main Controller
 Contract Creation0 ETH
1218758372024-06-25 21:20:51166 days ago1719350451  Contract Creation0 ETH

Loading...
Loading

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

Contract Name:
CDP Main Controller

Compiler Version
vyper:0.3.10

Optimization Enabled:
N/A

Other Settings:
default evmVersion, None license

Contract Source Code (Vyper language format)

#pragma version 0.3.10
"""
@title CDP Main Controller
@author Curve.Fi (with edits by defidotmoney)
@license Copyright (c) Curve.Fi, 2020-2024 - all rights reserved
"""

interface ERC20:
    def mint(_to: address, _value: uint256) -> bool: nonpayable
    def burn(_to: address, _value: uint256) -> bool: nonpayable
    def transferFrom(_from: address, _to: address, _value: uint256) -> bool: nonpayable
    def transfer(_to: address, _value: uint256) -> bool: nonpayable
    def balanceOf(account: address) -> uint256: view

interface PriceOracle:
    def price() -> uint256: view
    def price_w() -> uint256: nonpayable

interface AMM:
    def initialize(
        operator: address,
        oracle: PriceOracle,
        collateral: address,
        _base_price: uint256,
        fee: uint256,
        admin_fee: uint256
    ): nonpayable
    def set_rate(rate: uint256) -> uint256: nonpayable
    def price_oracle() -> uint256: view
    def rate() -> uint256: view
    def get_sum_xy(account: address) -> (uint256, uint256): view
    def read_user_tick_numbers(receiver: address) -> int256[2]: view
    def p_oracle_up(n: int256) -> uint256: view
    def p_oracle_down(n: int256) -> uint256: view
    def A() -> uint256: view

interface MarketOperator:
    def initialize(
        amm: address,
        collateral_token: address,
        debt_ceiling: uint256,
        loan_discount: uint256,
        liquidation_discount: uint256,
    ): nonpayable
    def total_debt() -> uint256: view
    def pending_debt() -> uint256: view
    def debt_ceiling() -> uint256: view
    def debt(account: address) -> uint256: view
    def max_borrowable(collateral: uint256, n_bands: uint256) -> uint256: view
    def health(account: address, full: bool) -> int256: view
    def collect_fees() -> (uint256, uint256[2]): nonpayable
    def create_loan(account: address, coll_amount: uint256, debt_amount: uint256, n_bands: uint256) -> uint256: nonpayable
    def adjust_loan(account: address, coll_amount: int256, debt_amount: int256, max_active_band: int256) -> int256: nonpayable
    def close_loan(account: address) -> (int256, uint256, uint256[2]): nonpayable
    def liquidate(caller: address, target: address, min_x: uint256, frac: uint256) -> (int256, uint256, uint256[2]): nonpayable
    def AMM() -> address: view
    def A() -> uint256: view
    def pending_account_state_calculator(
        account: address,
        coll_change: int256,
        debt_change: int256,
        num_bands: uint256
    ) -> (uint256, uint256, uint256, int256, int256[2]): view

interface MonetaryPolicy:
    def rate(market: MarketOperator) -> uint256: view
    def rate_write(market: address) -> uint256: nonpayable

interface PegKeeper:
    def set_regulator(regulator: address): nonpayable

interface PegKeeperRegulator:
    def active_debt() -> uint256: view
    def get_peg_keepers_with_debt_ceilings() -> (DynArray[PegKeeper, 256], DynArray[uint256, 256]): view
    def init_migrate_peg_keepers(peg_keepers: DynArray[PegKeeper, 256], debt_ceilings: DynArray[uint256, 256]): nonpayable

interface CoreOwner:
    def owner() -> address: view
    def feeReceiver() -> address: view
    def guardian() -> address: view

interface MarketHook:
    def get_configuration() -> (uint256, bool[NUM_HOOK_IDS]): view



event AddMarket:
    collateral: indexed(address)
    market: address
    amm: address
    mp_idx: uint256

event SetDelegateApproval:
    account: indexed(address)
    delegate: indexed(address)
    is_approved: bool

event SetDelegationEnabled:
    caller: address
    is_enabled: bool

event SetProtocolEnabled:
    caller: address
    is_enabled: bool

event SetImplementations:
    A: indexed(uint256)
    amm: address
    market: address

event AddMarketHook:
    market: indexed(address)
    hook: indexed(address)
    hook_type: uint256
    active_hooks: bool[NUM_HOOK_IDS]

event RemoveMarketHook:
    market: indexed(address)
    hook: indexed(address)
    hook_debt_released: uint256

event HookDebtAjustment:
    market: indexed(address)
    hook: indexed(address)
    adjustment: int256
    new_hook_debt: uint256
    new_total_hook_debt: uint256

event AddMonetaryPolicy:
    mp_idx: indexed(uint256)
    monetary_policy: MonetaryPolicy

event ChangeMonetaryPolicy:
    mp_idx: indexed(uint256)
    monetary_policy: MonetaryPolicy

event ChangeMonetaryPolicyForMarket:
    market: indexed(address)
    mp_idx: indexed(uint256)

event SetGlobalMarketDebtCeiling:
    debt_ceiling: uint256

event SetPegKeeperRegulator:
    regulator: address
    with_migration: bool

event CreateLoan:
    market: indexed(address)
    account: indexed(address)
    caller: indexed(address)
    coll_amount: uint256
    debt_amount: uint256

event AdjustLoan:
    market: indexed(address)
    account: indexed(address)
    caller: indexed(address)
    coll_adjustment: int256
    debt_adjustment: int256

event CloseLoan:
    market: indexed(address)
    account: indexed(address)
    caller: indexed(address)
    coll_withdrawn: uint256
    debt_withdrawn: uint256
    debt_repaid: uint256

event LiquidateLoan:
    market: indexed(address)
    liquidator: indexed(address)
    account: indexed(address)
    coll_received: uint256
    debt_received: uint256
    debt_repaid: uint256

event CollectAmmFees:
    market: indexed(address)
    amm_coll_fees: uint256
    amm_debt_fees: uint256

event CollectFees:
    minted: uint256
    redeemed: uint256
    total_debt: uint256
    fee: uint256


struct MarketContracts:
    collateral: address
    amm: address
    mp_idx: uint256

struct Implementations:
    amm: address
    market_operator: address

struct MarketHookData:
    hooks: address
    hook_type: uint256
    active_hooks: bool[NUM_HOOK_IDS]


enum HookId:
    ON_CREATE_LOAN
    ON_ADJUST_LOAN
    ON_CLOSE_LOAN
    ON_LIQUIDATION

enum HookType:
    VALIDATION_ONLY
    FEE_ONLY
    FEE_AND_REBATE


NUM_HOOK_IDS: constant(uint256) = 4
MAX_HOOKS: constant(uint256) = 4

# Limits
MIN_A: constant(uint256) = 2
MAX_A: constant(uint256) = 10000
MAX_RATE: constant(uint256) = 43959106799  # 300% APY
MIN_FEE: constant(uint256) = 10**6  # 1e-12, still needs to be above 0
MAX_FEE: constant(uint256) = 10**17  # 10%
MAX_ADMIN_FEE: constant(uint256) = 10**18  # 100%
MAX_LOAN_DISCOUNT: constant(uint256) = 5 * 10**17
MIN_LIQUIDATION_DISCOUNT: constant(uint256) = 10**16

STABLECOIN: public(immutable(ERC20))
CORE_OWNER: public(immutable(CoreOwner))
peg_keeper_regulator: public(PegKeeperRegulator)

markets: public(DynArray[MarketOperator, 65536])
collaterals: public(DynArray[address, 65536])
collateral_markets: HashMap[address, DynArray[address, 256]]
market_contracts: public(HashMap[address, MarketContracts])
monetary_policies: public(MonetaryPolicy[256])
n_monetary_policies: public(uint256)

global_market_debt_ceiling: public(uint256)
total_debt: public(uint256)
minted: public(uint256)
redeemed: public(uint256)

isApprovedDelegate: public(HashMap[address, HashMap[address, bool]])
isDelegationEnabled: public(bool)
is_protocol_enabled: public(bool)

implementations: HashMap[uint256, Implementations]

market_hooks: HashMap[address, DynArray[uint256, MAX_HOOKS]]
hook_debt: HashMap[address, HashMap[address, uint256]]
total_hook_debt: public(uint256)


@external
def __init__(
    core: CoreOwner,
    stable: ERC20,
    monetary_policies: DynArray[MonetaryPolicy, 10],
    debt_ceiling: uint256
):
    """
    @notice Contract constructor
    @param core `DFMProtocolCore` address. Ownership is inherited from this contract.
    @param stable Address of the protocol stablecoin. This contract must be given
                  minter privileges within the stablecoin.
    @param monetary_policies Array of `MonetaryPolicy` contracts to initially set.
    @param debt_ceiling Initial global debt ceiling
    """
    CORE_OWNER = core
    STABLECOIN = stable

    idx: uint256 = 0
    for mp in monetary_policies:
        log AddMonetaryPolicy(idx, mp)
        self.monetary_policies[idx] = mp
        idx += 1
    self.n_monetary_policies = idx

    self.global_market_debt_ceiling = debt_ceiling
    log SetGlobalMarketDebtCeiling(debt_ceiling)

    self.is_protocol_enabled = True
    self.isDelegationEnabled = True


# --- external view functions ---

@view
@external
def owner() -> address:
    return CORE_OWNER.owner()


@view
@external
def get_market_count() -> uint256:
    """
    @notice Get the total number of deployed markets
    """
    return len(self.markets)


@view
@external
def get_collateral_count() -> uint256:
    """
    @notice Get the number of unique collaterals used within the system
    @dev It is possible to deploy multiple markets for a collateral, so
         this number does not necessarily equal the number of markets.
    """
    return len(self.collaterals)


@view
@external
def get_all_markets() -> DynArray[MarketOperator, 65536]:
    """
    @notice Get a list of all deployed `MarketOperator` contracts
    """
    return self.markets


@view
@external
def get_all_collaterals() -> DynArray[address, 65536]:
    """
    @notice Get a list of collaterals for which a market exists
    """
    return self.collaterals


@view
@external
def get_all_markets_for_collateral(collateral: address) -> DynArray[address, 256]:
    """
    @notice Get a list of all deployed `MarketOperator` contracts
            that use a given collateral
    """
    return self.collateral_markets[collateral]


@view
@external
def get_market(collateral: address, i: uint256 = 0) -> address:
    """
    @notice Get market address for collateral
    @dev Returns empty(address) if market does not exist
    @param collateral Address of collateral token
    @param i Access the i-th market within the list
    """
    if i >= len(self.collateral_markets[collateral]):
        return empty(address)
    return self.collateral_markets[collateral][i]


@view
@external
def get_amm(collateral: address, i: uint256 = 0) -> address:
    """
    @notice Get AMM address for collateral
    @dev Returns empty(address) if market does not exist
    @param collateral Address of collateral token
    @param i Access the i-th collateral within the list
    """
    if i >= len(self.collateral_markets[collateral]):
        return empty(address)
    market: address = self.collateral_markets[collateral][i]
    return self.market_contracts[market].amm


@view
@external
def get_collateral(market: address) -> address:
    """
    @notice Get collateral token for a market
    @dev Returns empty(address) if market does not exist
    @param market Market address
    @return Address of collateral token
    """
    return self.market_contracts[market].collateral


@view
@external
def get_oracle_price(collateral: address) -> uint256:
    """
    @notice Get the current oracle price for `collateral`
    @dev Uses the AMM of the first market created for this collateral.
         Reverts if there is no existing market.
    @param collateral Address of collateral token
    @return Oracle price of `collateral` with 1e18 precision
    """
    market: address = self.collateral_markets[collateral][0]
    return AMM(self.market_contracts[market].amm).price_oracle()


@view
@external
def max_borrowable(market: MarketOperator, coll_amount: uint256, n_bands: uint256) -> uint256:
    """
    @notice Calculation of maximum which can be borrowed in the given market
    @param market Market where the loan will be taken
    @param coll_amount Collateral amount against which to borrow
    @param n_bands number of bands the collateral will be deposited over
    @return Maximum amount of stablecoin that can be borrowed
    """
    debt_ceiling: uint256 = self.global_market_debt_ceiling
    total_debt: uint256 = self.total_debt + market.pending_debt()
    if total_debt >= debt_ceiling:
        return 0

    global_max: uint256 = debt_ceiling - total_debt
    market_max: uint256 = market.max_borrowable(coll_amount, n_bands)

    return min(global_max, market_max)


@view
@external
def get_implementations(A: uint256) -> Implementations:
    """
    @notice Get the `MarketOperator` and `AMM` implementation contracts used
            when deploying a market with the given amplification coefficient.
    @return (AMM address, MarketOperator address)
    """
    return self.implementations[A]


@view
@external
def get_market_hooks(market: address) -> DynArray[MarketHookData, MAX_HOOKS]:
    """
    @notice Get the hook contracts and active hooks for the given market
    @param market Market address. Set as empty(address) for global hooks.
    @return market hooks
    """
    hookdata_packed_array: DynArray[uint256, MAX_HOOKS] = self.market_hooks[market]
    hookdata_array: DynArray[MarketHookData, MAX_HOOKS] = []


    for hookdata_packed in hookdata_packed_array:
        hookdata: MarketHookData = empty(MarketHookData)
        hookdata.hooks = self._get_hook_address(hookdata_packed)
        hookdata.hook_type = (hookdata_packed & 7) >> 1

        for i in range(NUM_HOOK_IDS):
            if hookdata_packed >> i & 8 != 0:
                hookdata.active_hooks[i] = True

        hookdata_array.append(hookdata)

    return hookdata_array


@view
@external
def get_market_hook_debt(market: address, hook: address) -> uint256:
    """
    @notice Get the total aggregate hook debt adjustments for the given market
    @dev The sum of all hook debt adjustments cannot ever be less than zero
         or the system will have uncollateralized debt.
    """
    return self.hook_debt[market][hook]


@view
@external
def get_monetary_policy_for_market(market: address) -> MonetaryPolicy:
    """
    @notice Get the address of the monetary policy for `market`
    """
    c: MarketContracts = self.market_contracts[market]

    if c.collateral == empty(address):
        return empty(MonetaryPolicy)

    return self.monetary_policies[c.mp_idx]


@view
@external
def get_peg_keeper_active_debt() -> uint256:
    """
    @notice Get the total active debt across all peg keepers
    """
    regulator: PegKeeperRegulator = self.peg_keeper_regulator
    if regulator.address == empty(address):
        return 0
    return regulator.active_debt()


@view
@external
def stored_admin_fees() -> uint256:
    """
    @notice Calculate the amount of fees obtained from the interest
    """
    return self.total_debt + self.redeemed - self.minted - self.total_hook_debt


@view
@external
def get_close_loan_amounts(account: address, market: address) -> (int256, uint256):
    """
    @notice Get balance information related to closing a loan
    @param account The account to close the loan for
    @param market Market of the loan being closed
    @return Debt balance change for caller
             * negative value indicates the amount burned to close
             * positive value indicates a surplus from the AMM after closing
            Collateral balance received from AMM
    """
    amm: AMM = AMM(self._get_market_contracts_or_revert(market).amm)
    xy: (uint256, uint256) = amm.get_sum_xy(account)

    debt: uint256 = MarketOperator(market).debt(account)
    hook_debt_adjustment: int256 = self._call_view_hooks(
        market,
        HookId.ON_CLOSE_LOAN,
        _abi_encode(account, market, debt, method_id=method_id("on_close_loan_view(address,address,uint256)")),
        self._positive_only_bounds(debt)
    )
    debt = self._uint_plus_int(debt, hook_debt_adjustment)

    return convert(xy[0], int256) - convert(debt, int256), xy[1]


@view
@external
def on_create_loan_hook_adjustment(
    account: address,
    market: address,
    coll_amount: uint256,
    debt_amount: uint256,
) -> int256:
    """
    @notice Get the aggregate hook debt adjustment when creating a new loan
    @param account Account to open the loan for
    @param market Market where the loan will be opened
    @param coll_amount Collateral amount to deposit
    @param debt_amount Stablecoin amount to mint
    @return adjustment amount applied to the new debt created
    """
    return self._call_view_hooks(
        market,
        HookId.ON_CREATE_LOAN,
        _abi_encode(
            account,
            market,
            coll_amount,
            debt_amount,
            method_id=method_id("on_create_loan_view(address,address,uint256,uint256)")
        ),
        self._positive_only_bounds(debt_amount)
    )


@view
@external
def on_adjust_loan_hook_adjustment(
    account: address,
    market: address,
    coll_change: int256,
    debt_change: int256
) -> int256:
    """
    @notice Get the aggregate hook debt adjustment when adjusting an existing loan
    @param account Account to adjust the loan for
    @param market Market of the loan being adjusted
    @param coll_change Collateral adjustment amount. A positive value deposits, negative withdraws.
    @param debt_change Debt adjustment amount. A positive value mints, negative burns.
    @return adjustment amount applied to `debt_change`
    """
    return self._call_view_hooks(
        market,
        HookId.ON_ADJUST_LOAN,
        _abi_encode(
            account,
            market,
            coll_change,
            debt_change,
            method_id=method_id("on_adjust_loan_view(address,address,int256,int256)")
        ),
        self._adjust_loan_bounds(debt_change)
    )


@view
@external
def on_close_loan_hook_adjustment(account: address, market: address) -> int256:
    """
    @notice Get the aggregate hook debt adjustment when closing a loan
    @param account The account to close the loan for
    @param market Market of the loan being closed
    @return adjustment amount applied to the debt burned when closing the loan
    """
    debt: uint256 = MarketOperator(market).debt(account)
    return self._call_view_hooks(
        market,
        HookId.ON_CLOSE_LOAN,
        _abi_encode(account, market, debt, method_id=method_id("on_close_loan_view(address,address,uint256)")),
        self._positive_only_bounds(debt)
    )


@view
@external
def on_liquidate_hook_adjustment(caller: address, market: address, target: address) -> int256:
    """
    @notice Get the aggregate hook debt adjustment when liquidating a loan
    @param caller Caller address that will perform the liquidations
    @param market Market to check for liquidations
    @param target Address of the account to be liquidated
    @return adjustment amount applied to the debt burned during liquidation
    """
    debt: uint256 = MarketOperator(market).debt(target)
    return self._call_view_hooks(
        market,
        HookId.ON_LIQUIDATION,
        _abi_encode(
            caller,
            market,
            target,
            debt,
            method_id=method_id("on_liquidation_view(address,address,address,uint256)")
        ),
        self._positive_only_bounds(debt)
    )


# --- unguarded nonpayable functions ---

@external
def setDelegateApproval(delegate: address, is_approved: bool):
    """
    @dev Functions that supports delegation include an `account` input allowing
         the delegated caller to indicate who they are calling on behalf of.
         In executing the call, all internal state updates are applied for
         `account` and all value transfers occur to or from the caller.

        For example: a delegated call to `create_loan` will transfer collateral
        from the caller, create the debt position for `account`, and send newly
        minted stablecoins to the caller.
    """
    self.isApprovedDelegate[msg.sender][delegate] = is_approved
    log SetDelegateApproval(msg.sender, delegate, is_approved)


@external
@nonreentrant('lock')
def create_loan(
    account: address,
    market: address,
    coll_amount: uint256,
    debt_amount: uint256,
    n_bands: uint256
):
    """
    @notice Create loan
    @param account Account to open the loan for
    @param market Market where the loan will be opened
    @param coll_amount Collateral amount to deposit
    @param debt_amount Stablecoin amount to mint
    @param n_bands Number of bands to deposit collateral into
                   Can be from market.MIN_TICKS() to market.MAX_TICKS()
    """
    assert coll_amount > 0 and debt_amount > 0, "DFM:C 0 coll or debt"
    self._assert_is_protocol_enabled()
    self._assert_caller_or_approved_delegate(account)
    c: MarketContracts = self._get_market_contracts_or_revert(market)

    hook_adjust: int256 = self._call_hooks(
        market,
        HookId.ON_CREATE_LOAN,
        _abi_encode(
            account,
            market,
            coll_amount,
            debt_amount,
            method_id=method_id("on_create_loan(address,address,uint256,uint256)")
        ),
        self._positive_only_bounds(debt_amount)
    )
    debt_amount_final: uint256 = self._uint_plus_int(debt_amount, hook_adjust)

    self._deposit_collateral(msg.sender, c.collateral, c.amm, coll_amount)
    debt_increase: uint256 = MarketOperator(market).create_loan(account, coll_amount, debt_amount_final, n_bands)

    total_debt: uint256 = self.total_debt + debt_increase
    self._assert_below_debt_ceiling(total_debt)

    self.total_debt = total_debt
    self.minted += debt_amount

    STABLECOIN.mint(msg.sender, debt_amount)

    self._update_rate(market, c.amm, c.mp_idx)

    log CreateLoan(market, account, msg.sender, coll_amount, debt_amount_final)


@external
@nonreentrant('lock')
def adjust_loan(
    account: address,
    market: address,
    coll_change: int256,
    debt_change: int256,
    max_active_band: int256 = max_value(int256)
):
    """
    @notice Adjust collateral/debt amounts for an existing loan
    @param account Account to adjust the loan for
    @param market Market of the loan being adjusted
    @param coll_change Collateral adjustment amount. A positive value deposits, negative withdraws.
    @param debt_change Debt adjustment amount. A positive value mints, negative burns.
    @param max_active_band Maximum active band (used to prevent front-running)
    """
    assert coll_change != 0 or debt_change != 0, "DFM:C No change"

    self._assert_is_protocol_enabled()
    self._assert_caller_or_approved_delegate(account)
    c: MarketContracts = self._get_market_contracts_or_revert(market)

    debt_change_final: int256 = self._call_hooks(
        market,
        HookId.ON_ADJUST_LOAN,
        _abi_encode(
            account,
            market,
            coll_change,
            debt_change,
            method_id=method_id("on_adjust_loan(address,address,int256,int256)")
        ),
        self._adjust_loan_bounds(debt_change)
    ) + debt_change

    debt_adjustment: int256 = MarketOperator(market).adjust_loan(account, coll_change, debt_change_final, max_active_band)

    total_debt: uint256 = self._uint_plus_int(self.total_debt, debt_adjustment)
    self.total_debt = total_debt

    if debt_change != 0:
        debt_change_abs: uint256 = convert(abs(debt_change), uint256)
        if debt_change > 0:
            self._assert_below_debt_ceiling(total_debt)
            self.minted += debt_change_abs
            STABLECOIN.mint(msg.sender, debt_change_abs)
        else:
            self.redeemed += debt_change_abs
            STABLECOIN.burn(msg.sender, debt_change_abs)

    if coll_change != 0:
        coll_change_abs: uint256 = convert(abs(coll_change), uint256)
        if coll_change > 0:
            self._deposit_collateral(msg.sender, c.collateral, c.amm, coll_change_abs)
        else:
            self._withdraw_collateral(msg.sender, c.collateral, c.amm, coll_change_abs)

    self._update_rate(market, c.amm, c.mp_idx)

    log AdjustLoan(market, account, msg.sender, coll_change, debt_change_final)


@external
@nonreentrant('lock')
def close_loan(account: address, market: address) -> (int256, uint256):
    """
    @notice Close an existing loan
    @dev This function does not interact with the market's price oracle, so that
         users can still close their loans in case of a reverting oracle.
    @param account The account to close the loan for
    @param market Market of the loan being closed
    @return Debt balance change for caller
             * negative value indicates the amount burned to close
             * positive value indicates a surplus from the AMM after closing
            Collateral balance received from AMM
    """
    self._assert_caller_or_approved_delegate(account)
    c: MarketContracts = self._get_market_contracts_or_revert(market)

    debt_adjustment: int256 = 0
    burn_amount: uint256 = 0
    xy: uint256[2] = empty(uint256[2])
    debt_adjustment, burn_amount, xy = MarketOperator(market).close_loan(account)

    burn_adjust: int256 = self._call_hooks(
        market,
        HookId.ON_CLOSE_LOAN,
        _abi_encode(account, market, burn_amount, method_id=method_id("on_close_loan(address,address,uint256)")),
        self._positive_only_bounds(burn_amount)
    )
    burn_amount = self._uint_plus_int(burn_amount, burn_adjust)

    self.redeemed += burn_amount
    self.total_debt = self._uint_plus_int(self.total_debt, debt_adjustment)

    if xy[0] > 0:
        STABLECOIN.transferFrom(c.amm, msg.sender, xy[0])
    STABLECOIN.burn(msg.sender, burn_amount)
    if xy[1] > 0:
        self._withdraw_collateral(msg.sender, c.collateral, c.amm, xy[1])

    self._update_rate(market, c.amm, c.mp_idx)

    log CloseLoan(market, account, msg.sender, xy[1], xy[0], burn_amount)

    return convert(xy[0], int256) - convert(burn_amount, int256), xy[1]


@external
@nonreentrant('lock')
def liquidate(market: address, target: address, min_x: uint256, frac: uint256 = 10**18) -> (int256, uint256):
    """
    @notice Perform a liquidation (or self-liquidation) on an unhealthy account
    @param market Market of the loan being liquidated
    @param target Address of the account to be liquidated
    @param min_x Minimal amount of stablecoin to receive (to avoid liquidators being sandwiched)
    @param frac Fraction to liquidate; 100% = 10**18
    @return Debt balance change for caller
             * negative value indicates the amount burned to liquidate
             * positive value indicates a surplus received from the AMM
            Collateral balance received from AMM
    """
    assert frac <= 10**18, "DFM:C frac too high"
    c: MarketContracts = self._get_market_contracts_or_revert(market)

    debt_adjustment: int256 = 0
    debt_amount: uint256 = 0
    xy: uint256[2] = empty(uint256[2])
    debt_adjustment, debt_amount, xy = MarketOperator(market).liquidate(msg.sender, target, min_x, frac)

    burn_adjust: int256 = self._call_hooks(
        market,
        HookId.ON_LIQUIDATION,
        _abi_encode(
            msg.sender,
            market,
            target,
            debt_amount,
            method_id=method_id("on_liquidation(address,address,address,uint256)")
        ),
        self._positive_only_bounds(debt_amount)
    )
    debt_amount = self._uint_plus_int(debt_amount, burn_adjust)

    self.redeemed += debt_amount
    self.total_debt = self._uint_plus_int(self.total_debt, debt_adjustment)

    burn_amm: uint256 = min(xy[0], debt_amount)
    if burn_amm != 0:
        STABLECOIN.burn(c.amm, burn_amm)

    if debt_amount > xy[0]:
        remaining: uint256 = unsafe_sub(debt_amount, xy[0])
        STABLECOIN.burn(msg.sender, remaining)
    elif xy[0] > debt_amount:
        STABLECOIN.transferFrom(c.amm, msg.sender, unsafe_sub(xy[0], debt_amount))

    if xy[1] > 0:
        self._withdraw_collateral(msg.sender, c.collateral, c.amm, xy[1])

    self._update_rate(market, c.amm, c.mp_idx)

    log LiquidateLoan(market, msg.sender, target, xy[1], xy[0], debt_amount)

    return convert(xy[0], int256) - convert(debt_amount, int256), xy[1]


@external
@nonreentrant('lock')
def collect_fees(market_list: DynArray[address, 255]) -> uint256:
    """
    @notice Collect admin fees across markets
    @param market_list List of markets to collect fees from. Can be left empty
                       to only claim already-stored interest fees.
    """
    self._assert_is_protocol_enabled()

    receiver: address = CORE_OWNER.feeReceiver()

    debt_increase_total: uint256 = 0
    i: uint256 = 0
    amm_list: address[255] = empty(address[255])
    mp_idx_list: uint256[255] = empty(uint256[255])

    # collect market fees and calculate aggregate debt increase
    for market in market_list:
        c: MarketContracts = self._get_market_contracts_or_revert(market)

        debt_increase: uint256 = 0
        xy: uint256[2] = empty(uint256[2])

        debt_increase, xy = MarketOperator(market).collect_fees()
        debt_increase_total += debt_increase

        if xy[0] > 0:
            STABLECOIN.transferFrom(c.amm, receiver, xy[0])
        if xy[1] > 0:
            self._withdraw_collateral(receiver, c.collateral, c.amm, xy[1])

        log CollectAmmFees(market, xy[1], xy[0])

        amm_list[i] = c.amm
        mp_idx_list[i] = c.mp_idx
        i = unsafe_add(i, 1)

    # update total debt and market rates
    total_debt: uint256 = self.total_debt + debt_increase_total
    self.total_debt = total_debt

    mint_total: uint256 = 0
    minted: uint256 = self.minted
    redeemed: uint256 = self.redeemed
    to_be_redeemed: uint256 = total_debt + redeemed - self.total_hook_debt

    if to_be_redeemed > minted:
        self.minted = to_be_redeemed
        mint_total = unsafe_sub(to_be_redeemed, minted)  # Now this is the fees to charge
        STABLECOIN.mint(receiver, mint_total)

    i = 0
    for market in market_list:
        self._update_rate(market, amm_list[i], mp_idx_list[i])
        i = unsafe_add(i, 1)

    log CollectFees(minted, redeemed, total_debt, mint_total)
    return mint_total


@external
def increase_hook_debt(market: address, hook: address, amount: uint256):
    """
    @notice Burn debt to increase the available hook debt value for a given
            market hook. This can be used to pre-fund hook debt rebates.
    """
    if market != empty(address):
        self._assert_market_exists(market)

    num_hooks: uint256 = len(self.market_hooks[market])
    for i in range(MAX_HOOKS + 1):
        if i == num_hooks:
            raise "DFM:C Unknown hook"
        hookdata: uint256 = self.market_hooks[market][i]
        if self._get_hook_address(hookdata) == hook:
            assert self._get_hook_type(hookdata) == HookType.FEE_AND_REBATE, "DFM:C Hook does not track debt"
            break

    STABLECOIN.burn(msg.sender, amount)
    self.hook_debt[market][hook] += amount
    self.total_hook_debt += amount
    self.redeemed += amount


# --- owner-only nonpayable functions ---

@external
def add_market(token: address, A: uint256, fee: uint256, admin_fee: uint256, oracle: PriceOracle,
               mp_idx: uint256, loan_discount: uint256, liquidation_discount: uint256,
               debt_ceiling: uint256) -> address[2]:
    """
    @notice Add a new market, creating an AMM and a MarketOperator from a blueprint
    @param token Collateral token address
    @param A Amplification coefficient; one band size is 1/A
    @param fee AMM fee in the market's AMM
    @param admin_fee AMM admin fee
    @param oracle Address of price oracle contract for this market
    @param mp_idx Monetary policy index for this market
    @param loan_discount Loan discount: allowed to borrow only up to x_down * (1 - loan_discount)
    @param liquidation_discount Discount which defines a bad liquidation threshold
    @param debt_ceiling Debt ceiling for this market
    @return (MarketOperator, AMM)
    """
    self._assert_only_owner()
    assert fee <= MAX_FEE, "DFM:C Fee too high"
    assert fee >= MIN_FEE, "DFM:C Fee too low"
    assert admin_fee <= MAX_ADMIN_FEE, "DFM:C Admin fee too high"
    assert liquidation_discount >= MIN_LIQUIDATION_DISCOUNT, "DFM:C liq discount too low"
    assert loan_discount <= MAX_LOAN_DISCOUNT, "DFM:C Loan discount too high"
    assert loan_discount > liquidation_discount, "DFM:C loan discount<liq discount"
    assert mp_idx < self.n_monetary_policies, "DFM:C invalid mp_idx"

    p: uint256 = oracle.price()
    assert p > 0, "DFM:C p == 0"
    assert oracle.price_w() == p, "DFM:C p != price_w"

    impl: Implementations = self.implementations[A]
    assert impl.amm != empty(address), "DFM:C No implementation for A"

    # deploy with `CREATE2` and include `chain.id` in the salt to ensure unique `MarketOperator`
    # and `AMM` addresses, even if the controller is deployed at the same address on each chain
    salt_num: uint256 = (chain.id << 176) + (convert(token, uint256) << 16) + len(self.collateral_markets[token])
    market: address = create_minimal_proxy_to(impl.market_operator, salt=keccak256(convert(salt_num, bytes32)))
    amm: address = create_minimal_proxy_to(impl.amm, salt= keccak256(convert(salt_num << 8, bytes32)))

    MarketOperator(market).initialize(amm, token, debt_ceiling, loan_discount, liquidation_discount)
    AMM(amm).initialize(market, oracle, token, p, fee, admin_fee)

    self.markets.append(MarketOperator(market))
    if len(self.collateral_markets[token]) == 0:
        self.collaterals.append(token)
    self.collateral_markets[token].append(market)
    self.market_contracts[market] = MarketContracts({collateral: token, amm: amm, mp_idx: mp_idx})

    log AddMarket(token, market, amm, mp_idx)
    return [market, amm]


@external
def set_global_market_debt_ceiling(debt_ceiling: uint256):
    """
    @notice Set the global debt ceiling
    @dev There is no requirement for the global ceiling to be equal to the sum
         of the market ceilings. Individual markets may mint up to their own debt
         ceiling, so long as the aggregate debt does not exceed the global ceiling.
    """
    self._assert_only_owner()
    self.global_market_debt_ceiling = debt_ceiling

    log SetGlobalMarketDebtCeiling(debt_ceiling)


@external
def set_implementations(A: uint256, market: address, amm: address):
    """
    @notice Set new implementations for market and amm for given A
    @dev Already-deployed markets are unaffected by this change
    @param A Amplification co-efficient
    @param market Address of the market blueprint
    @param amm Address of the AMM blueprint
    """
    self._assert_only_owner()
    assert A >= MIN_A and A <= MAX_A, "DFM:C A outside bounds"

    if amm == market:
        assert amm == empty(address), "DFM:C matching implementations"
    else:
        assert amm != empty(address) and market != empty(address), "DFM:C empty implementation"
        assert MarketOperator(market).A() == A, "DFM:C incorrect market A"
        assert AMM(amm).A() == A, "DFM:C incorrect amm A"

    self.implementations[A] = Implementations({amm: amm, market_operator: market})
    log SetImplementations(A, amm, market)


@external
def add_market_hook(market: address, hook: address):
    """
    @notice Add a new callback hook contract for `market`
    @dev Hook contracts must adhere to the interface and specification defined
         at `interfaces/IControllerHooks.sol`
    @param market Market to add a hook for. Use empty(address) to set a global hook.
    @param hook Address of the hook contract.
    """
    self._assert_only_owner()

    if market != empty(address):
        self._assert_market_exists(market)

    market_hooks: DynArray[uint256, MAX_HOOKS] = self.market_hooks[market]
    assert len(market_hooks) < MAX_HOOKS, "DFM:C Maximum hook count reached"
    for hookdata in market_hooks:
        assert self._get_hook_address(hookdata) != hook, "DFM:C Hook already added"

    config: (uint256, bool[NUM_HOOK_IDS]) = MarketHook(hook).get_configuration()

    # add hook type to 3 lowest bits
    assert config[0] < 3, "DFM:C Invalid hook type"
    hookdata_packed: uint256 = 1 << config[0]

    # add hook ids starting from 4th bit
    for i in range(NUM_HOOK_IDS):
        if config[1][i]:
            hookdata_packed += 1 << (i + 3)

    assert (hookdata_packed >> 3) > 0, "DFM:C No active hook points"

    # add address starting from 96th bit
    hookdata_packed += convert(hook, uint256) << 96

    self.market_hooks[market].append(hookdata_packed)

    log AddMarketHook(market, hook, config[0], config[1])


@external
def remove_market_hook(market: address, hook: address):
    """
    @notice Remove a callback hook contract for `market`
    @dev If the hook type is `FEE_AND_REBATE` and the current `hook_debt`
         is non-zero, is balance is creditted to the protocol fees.
    @param market Market to remove the hooks from. Set as empty(address) to
                  remove a global hook.
    @param hook Address of the hook contract.
    """
    self._assert_only_owner()

    if market != empty(address):
        self._assert_market_exists(market)

    num_hooks: uint256 = len(self.market_hooks[market])
    for i in range(MAX_HOOKS + 1):
        if i == num_hooks:
            raise "DFM:C Unknown hook"
        if self._get_hook_address(self.market_hooks[market][i]) != hook:
            continue

        last_hookdata: uint256 = self.market_hooks[market].pop()
        if i < num_hooks - 1:
            self.market_hooks[market][i] = last_hookdata
        break

    hook_debt: uint256 = self.hook_debt[market][hook]
    if hook_debt > 0:
        self._adjust_hook_debt(market, hook, -convert(hook_debt, int256))

    log RemoveMarketHook(market, hook, hook_debt)



@external
def add_new_monetary_policy(monetary_policy: MonetaryPolicy):
    """
    @notice Add a new monetary policy
    @dev The new policy is assigned an identifier `mp_idx` which is used to
         associate it to individual markets
    """
    self._assert_only_owner()
    idx: uint256 = self.n_monetary_policies
    self.monetary_policies[idx] = monetary_policy
    self.n_monetary_policies = idx +1

    log AddMonetaryPolicy(idx, monetary_policy)


@external
def change_existing_monetary_policy(monetary_policy: MonetaryPolicy, mp_idx: uint256):
    """
    @notice Change the monetary policy at an existing `mp_idx`
    @dev Rates for markets using `mp_idx` are NOT updated,
         it is recommended to force an update via `collect_fees`
    """
    self._assert_only_owner()
    assert mp_idx < self.n_monetary_policies, "DFM:C invalid mp_idx"
    self.monetary_policies[mp_idx] = monetary_policy

    log ChangeMonetaryPolicy(mp_idx, monetary_policy)


@external
def change_market_monetary_policy(market: address, mp_idx: uint256):
    """
    @notice Modify the assigned `mp_idx` for the given market
    @dev Also updates the current market rate
    """
    self._assert_only_owner()
    self._assert_market_exists(market)
    assert mp_idx < self.n_monetary_policies, "DFM:C invalid mp_idx"

    self.market_contracts[market].mp_idx = mp_idx
    self._update_rate(market, self.market_contracts[market].amm, mp_idx)

    log ChangeMonetaryPolicyForMarket(market, mp_idx)


@external
def set_peg_keeper_regulator(regulator: PegKeeperRegulator, with_migration: bool):
    """
    @notice Set the active peg keeper regulator
    @dev The regulator must also be given permission to mint `STABLECOIN`
    @param regulator Address of the new peg keeper regulator. Can also be set to
                     empty(address) to have no active regulator.
    @param with_migration if True, all peg keepers from the old regulator are
                          added to the new regulator with the same debt ceilings.
    """
    self._assert_only_owner()
    old: PegKeeperRegulator = self.peg_keeper_regulator
    assert old != regulator, "DFM:C regulator unchanged"

    if with_migration:
        peg_keepers: DynArray[PegKeeper, 256] = []
        debt_ceilings: DynArray[uint256, 256] = []
        (peg_keepers, debt_ceilings) = old.get_peg_keepers_with_debt_ceilings()
        for pk in peg_keepers:
            pk.set_regulator(regulator.address)
        regulator.init_migrate_peg_keepers(peg_keepers, debt_ceilings)

    self.peg_keeper_regulator = regulator

    log SetPegKeeperRegulator(regulator.address, with_migration)


@external
def set_protocol_enabled(is_enabled: bool):
    """
    @notice Enable or disable the protocol in case of an emergency.
    @dev * While disabled, `close_loan` and `liquidate` are the only callable
           functions related to loan management.
         * Only the owner can enable.
         * The owner and the guardian are both able to disable.
    """
    self._assert_owner_or_guardian_toggle(is_enabled)
    self.is_protocol_enabled = is_enabled

    log SetProtocolEnabled(msg.sender, is_enabled)


@external
def setDelegationEnabled(is_enabled: bool):
    """
    @notice Enable or disable all delegated operations within this contract
    @dev Delegated operations are enabled by default upon deployment.
         Only the owner can enable. The owner or the guardian can disable.
    """
    self._assert_owner_or_guardian_toggle(is_enabled)
    self.isDelegationEnabled = is_enabled

    log SetDelegationEnabled(msg.sender, is_enabled)



# --- internal functions ---

@view
@internal
def _assert_only_owner():
    assert msg.sender == CORE_OWNER.owner(), "DFM:C Only owner"


@view
@internal
def _assert_owner_or_guardian_toggle(is_enabled: bool):
    if msg.sender != CORE_OWNER.owner():
        if msg.sender == CORE_OWNER.guardian():
            assert not is_enabled, "DFM:C Guardian can only disable"
        else:
            raise "DFM:C Not owner or guardian"


@view
@internal
def _assert_is_protocol_enabled():
    assert self.is_protocol_enabled, "DFM:C Protocol pause, close only"



@view
@internal
def _assert_caller_or_approved_delegate(account: address):
    if msg.sender != account:
        assert self.isDelegationEnabled, "DFM:C Delegation disabled"
        assert self.isApprovedDelegate[account][msg.sender], "DFM:C Delegate not approved"


@view
@internal
def _assert_below_debt_ceiling(total_debt: uint256):
    assert total_debt <= self.global_market_debt_ceiling, "DFM:C global debt ceiling"


@pure
@internal
def _assert_in_bounds(amount: int256, bounds: int256[2], is_sum: bool):
    if amount < bounds[0] or amount > bounds[1]:
        if is_sum:
            raise "DFM:C hook sum out of bounds"
        else:
            raise "DFM:C Hook caused invalid debt"


@view
@internal
def _assert_market_exists(market: address):
    assert self.market_contracts[market].collateral != empty(address), "DFM:C Invalid market"


@pure
@internal
def _uint_plus_int(initial: uint256, adjustment: int256) -> uint256:
    if adjustment < 0:
        return initial - convert(-adjustment, uint256)
    else:
        return initial + convert(adjustment, uint256)


@pure
@internal
def _adjust_loan_bounds(debt_change: int256) -> int256[2]:
    if debt_change < 0:
        # when reducing debt, hook cannot cause a debt increase
        return [min_value(int256), -debt_change]
    if debt_change > 0:
        # when increasing debt, hook cannot cause a debt reduction
        return [-debt_change, max_value(int256)]
    # when debt is unchanged, hook cannot apply any adjustment
    return empty(int256[2])


@pure
@internal
def _positive_only_bounds(debt_amount: uint256) -> int256[2]:
    # hook adjustment cannot cause debt_amount to go below 0
    return [-convert(debt_amount, int256), max_value(int256)]


@view
@internal
def _get_market_contracts_or_revert(market: address) -> MarketContracts:
    c: MarketContracts = self.market_contracts[market]

    assert c.collateral != empty(address), "DFM:C Invalid market"

    return c


@view
@internal
def _get_hook_address(hookdata: uint256) -> address:
    # hook address is stored in the upper 160 bits
    return convert(hookdata >> 96, address)


@view
@internal
def _get_hook_type(hookdata: uint256) -> HookType:
    # hook type is indicated in the three lowest bits:
    # 0b001 == VALIDATION_ONLY (cannot adjust debt)
    # 0b010 == FEE_ONLY (can only increase debt, adjustment is added to fees)
    # 0b100 == FEE_AND_REBATE (can increase and decrease debt, aggregate sum tracked in `hook_debt`)
    return convert(hookdata & 7, HookType)


@view
@internal
def _is_hook_id_active(hookdata: uint256, hook_id: HookId) -> bool:
    # hook ids are tracked from the 4th bit onward
    return hookdata & (convert(hook_id, uint256) << 3) != 0


@view
@internal
def _call_view_hooks(market: address, hook_id: HookId, calldata: Bytes[255], bounds: int256[2]) -> int256:
    debt_adjustment: int256 = 0
    for market_hooks_key in [market, empty(address)]:
        hookdata_array: DynArray[uint256, MAX_HOOKS] = self.market_hooks[market_hooks_key]
        if len(hookdata_array) == 0:
            continue

        for hookdata in hookdata_array:
            if not self._is_hook_id_active(hookdata, hook_id):
                continue

            hook: address = self._get_hook_address(hookdata)
            response: int256 = convert(raw_call(hook, calldata, max_outsize=32, is_static_call=True), int256)
            if response == 0:
                continue

            hook_type: HookType = self._get_hook_type(hookdata)
            if hook_type == HookType.VALIDATION_ONLY:
                raise "DFM:C Hook cannot adjust debt"
            if hook_type == HookType.FEE_ONLY:
                self._assert_in_bounds(response, [0, bounds[1]], False)
            else:
                self._assert_in_bounds(response, bounds, False)
                if response < 0:
                    hook_debt: uint256 = self.hook_debt[market_hooks_key][hook]
                    assert hook_debt >= convert(-response, uint256), "DFM:C Hook debt underflow"

            debt_adjustment += response

    if debt_adjustment != 0:
        self._assert_in_bounds(debt_adjustment, bounds, True)

    return debt_adjustment


@internal
def _deposit_collateral(account: address, collateral: address, amm: address, amount: uint256):
    assert ERC20(collateral).transferFrom(account, amm, amount, default_return_value=True)


@internal
def _withdraw_collateral(account: address, collateral: address, amm: address, amount: uint256):
    assert ERC20(collateral).transferFrom(amm, account, amount, default_return_value=True)


@internal
def _call_hooks(
    market: address,
    hook_id: HookId,
    calldata: Bytes[255],
    bounds: int256[2]
) -> int256:
    debt_adjustment: int256 = 0
    for market_hooks_key in [market, empty(address)]:
        hookdata_array: DynArray[uint256, MAX_HOOKS] = self.market_hooks[market_hooks_key]
        if len(hookdata_array) == 0:
            continue

        for hookdata in hookdata_array:
            if not self._is_hook_id_active(hookdata, hook_id):
                continue

            hook: address = self._get_hook_address(hookdata)
            response: int256 = convert(raw_call(hook, calldata, max_outsize=32), int256)
            if response == 0:
                continue

            hook_type: HookType = self._get_hook_type(hookdata)
            if hook_type == HookType.VALIDATION_ONLY:
                raise "DFM:C Hook cannot adjust debt"
            if hook_type == HookType.FEE_ONLY:
                self._assert_in_bounds(response, [0, bounds[1]], False)
            else:
                self._assert_in_bounds(response, bounds, False)
                self._adjust_hook_debt(market_hooks_key, hook, response)

            debt_adjustment += response

    if debt_adjustment != 0:
        self._assert_in_bounds(debt_adjustment, bounds, True)

    return debt_adjustment


@internal
def _adjust_hook_debt(market: address, hook: address, adjustment: int256):
    hook_debt: uint256 = self.hook_debt[market][hook]
    if adjustment < 0:
        assert hook_debt >= convert(-adjustment, uint256), "DFM:C Hook debt underflow"

    hook_debt = self._uint_plus_int(hook_debt, adjustment)
    total_hook_debt: uint256 = self._uint_plus_int(self.total_hook_debt, adjustment)
    self.hook_debt[market][hook] = hook_debt
    self.total_hook_debt = total_hook_debt

    log HookDebtAjustment(market, hook, adjustment, hook_debt, total_hook_debt)


@internal
def _update_rate(market: address, amm: address, mp_idx: uint256):
    # rate update is always the final action in a function, so that the
    # monetary policy has an accurate view of the current state
    mp_rate: uint256 = min(self.monetary_policies[mp_idx].rate_write(market), MAX_RATE)
    AMM(amm).set_rate(mp_rate)

Contract Security Audit

Contract ABI

[{"name":"AddMarket","inputs":[{"name":"collateral","type":"address","indexed":true},{"name":"market","type":"address","indexed":false},{"name":"amm","type":"address","indexed":false},{"name":"mp_idx","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetDelegateApproval","inputs":[{"name":"account","type":"address","indexed":true},{"name":"delegate","type":"address","indexed":true},{"name":"is_approved","type":"bool","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetDelegationEnabled","inputs":[{"name":"caller","type":"address","indexed":false},{"name":"is_enabled","type":"bool","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetProtocolEnabled","inputs":[{"name":"caller","type":"address","indexed":false},{"name":"is_enabled","type":"bool","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetImplementations","inputs":[{"name":"A","type":"uint256","indexed":true},{"name":"amm","type":"address","indexed":false},{"name":"market","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"AddMarketHook","inputs":[{"name":"market","type":"address","indexed":true},{"name":"hook","type":"address","indexed":true},{"name":"hook_type","type":"uint256","indexed":false},{"name":"active_hooks","type":"bool[4]","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveMarketHook","inputs":[{"name":"market","type":"address","indexed":true},{"name":"hook","type":"address","indexed":true},{"name":"hook_debt_released","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"HookDebtAjustment","inputs":[{"name":"market","type":"address","indexed":true},{"name":"hook","type":"address","indexed":true},{"name":"adjustment","type":"int256","indexed":false},{"name":"new_hook_debt","type":"uint256","indexed":false},{"name":"new_total_hook_debt","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"AddMonetaryPolicy","inputs":[{"name":"mp_idx","type":"uint256","indexed":true},{"name":"monetary_policy","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"ChangeMonetaryPolicy","inputs":[{"name":"mp_idx","type":"uint256","indexed":true},{"name":"monetary_policy","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"ChangeMonetaryPolicyForMarket","inputs":[{"name":"market","type":"address","indexed":true},{"name":"mp_idx","type":"uint256","indexed":true}],"anonymous":false,"type":"event"},{"name":"SetGlobalMarketDebtCeiling","inputs":[{"name":"debt_ceiling","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetPegKeeperRegulator","inputs":[{"name":"regulator","type":"address","indexed":false},{"name":"with_migration","type":"bool","indexed":false}],"anonymous":false,"type":"event"},{"name":"CreateLoan","inputs":[{"name":"market","type":"address","indexed":true},{"name":"account","type":"address","indexed":true},{"name":"caller","type":"address","indexed":true},{"name":"coll_amount","type":"uint256","indexed":false},{"name":"debt_amount","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"AdjustLoan","inputs":[{"name":"market","type":"address","indexed":true},{"name":"account","type":"address","indexed":true},{"name":"caller","type":"address","indexed":true},{"name":"coll_adjustment","type":"int256","indexed":false},{"name":"debt_adjustment","type":"int256","indexed":false}],"anonymous":false,"type":"event"},{"name":"CloseLoan","inputs":[{"name":"market","type":"address","indexed":true},{"name":"account","type":"address","indexed":true},{"name":"caller","type":"address","indexed":true},{"name":"coll_withdrawn","type":"uint256","indexed":false},{"name":"debt_withdrawn","type":"uint256","indexed":false},{"name":"debt_repaid","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"LiquidateLoan","inputs":[{"name":"market","type":"address","indexed":true},{"name":"liquidator","type":"address","indexed":true},{"name":"account","type":"address","indexed":true},{"name":"coll_received","type":"uint256","indexed":false},{"name":"debt_received","type":"uint256","indexed":false},{"name":"debt_repaid","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"CollectAmmFees","inputs":[{"name":"market","type":"address","indexed":true},{"name":"amm_coll_fees","type":"uint256","indexed":false},{"name":"amm_debt_fees","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"CollectFees","inputs":[{"name":"minted","type":"uint256","indexed":false},{"name":"redeemed","type":"uint256","indexed":false},{"name":"total_debt","type":"uint256","indexed":false},{"name":"fee","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"stateMutability":"nonpayable","type":"constructor","inputs":[{"name":"core","type":"address"},{"name":"stable","type":"address"},{"name":"monetary_policies","type":"address[]"},{"name":"debt_ceiling","type":"uint256"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_market_count","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_collateral_count","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_all_markets","inputs":[],"outputs":[{"name":"","type":"address[]"}]},{"stateMutability":"view","type":"function","name":"get_all_collaterals","inputs":[],"outputs":[{"name":"","type":"address[]"}]},{"stateMutability":"view","type":"function","name":"get_all_markets_for_collateral","inputs":[{"name":"collateral","type":"address"}],"outputs":[{"name":"","type":"address[]"}]},{"stateMutability":"view","type":"function","name":"get_market","inputs":[{"name":"collateral","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_market","inputs":[{"name":"collateral","type":"address"},{"name":"i","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_amm","inputs":[{"name":"collateral","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_amm","inputs":[{"name":"collateral","type":"address"},{"name":"i","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_collateral","inputs":[{"name":"market","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_oracle_price","inputs":[{"name":"collateral","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"max_borrowable","inputs":[{"name":"market","type":"address"},{"name":"coll_amount","type":"uint256"},{"name":"n_bands","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_implementations","inputs":[{"name":"A","type":"uint256"}],"outputs":[{"name":"","type":"tuple","components":[{"name":"amm","type":"address"},{"name":"market_operator","type":"address"}]}]},{"stateMutability":"view","type":"function","name":"get_market_hooks","inputs":[{"name":"market","type":"address"}],"outputs":[{"name":"","type":"tuple[]","components":[{"name":"hooks","type":"address"},{"name":"hook_type","type":"uint256"},{"name":"active_hooks","type":"bool[4]"}]}]},{"stateMutability":"view","type":"function","name":"get_market_hook_debt","inputs":[{"name":"market","type":"address"},{"name":"hook","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_monetary_policy_for_market","inputs":[{"name":"market","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_peg_keeper_active_debt","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"stored_admin_fees","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_close_loan_amounts","inputs":[{"name":"account","type":"address"},{"name":"market","type":"address"}],"outputs":[{"name":"","type":"int256"},{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"on_create_loan_hook_adjustment","inputs":[{"name":"account","type":"address"},{"name":"market","type":"address"},{"name":"coll_amount","type":"uint256"},{"name":"debt_amount","type":"uint256"}],"outputs":[{"name":"","type":"int256"}]},{"stateMutability":"view","type":"function","name":"on_adjust_loan_hook_adjustment","inputs":[{"name":"account","type":"address"},{"name":"market","type":"address"},{"name":"coll_change","type":"int256"},{"name":"debt_change","type":"int256"}],"outputs":[{"name":"","type":"int256"}]},{"stateMutability":"view","type":"function","name":"on_close_loan_hook_adjustment","inputs":[{"name":"account","type":"address"},{"name":"market","type":"address"}],"outputs":[{"name":"","type":"int256"}]},{"stateMutability":"view","type":"function","name":"on_liquidate_hook_adjustment","inputs":[{"name":"caller","type":"address"},{"name":"market","type":"address"},{"name":"target","type":"address"}],"outputs":[{"name":"","type":"int256"}]},{"stateMutability":"nonpayable","type":"function","name":"setDelegateApproval","inputs":[{"name":"delegate","type":"address"},{"name":"is_approved","type":"bool"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"create_loan","inputs":[{"name":"account","type":"address"},{"name":"market","type":"address"},{"name":"coll_amount","type":"uint256"},{"name":"debt_amount","type":"uint256"},{"name":"n_bands","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"adjust_loan","inputs":[{"name":"account","type":"address"},{"name":"market","type":"address"},{"name":"coll_change","type":"int256"},{"name":"debt_change","type":"int256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"adjust_loan","inputs":[{"name":"account","type":"address"},{"name":"market","type":"address"},{"name":"coll_change","type":"int256"},{"name":"debt_change","type":"int256"},{"name":"max_active_band","type":"int256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"close_loan","inputs":[{"name":"account","type":"address"},{"name":"market","type":"address"}],"outputs":[{"name":"","type":"int256"},{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"liquidate","inputs":[{"name":"market","type":"address"},{"name":"target","type":"address"},{"name":"min_x","type":"uint256"}],"outputs":[{"name":"","type":"int256"},{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"liquidate","inputs":[{"name":"market","type":"address"},{"name":"target","type":"address"},{"name":"min_x","type":"uint256"},{"name":"frac","type":"uint256"}],"outputs":[{"name":"","type":"int256"},{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"collect_fees","inputs":[{"name":"market_list","type":"address[]"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"increase_hook_debt","inputs":[{"name":"market","type":"address"},{"name":"hook","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"add_market","inputs":[{"name":"token","type":"address"},{"name":"A","type":"uint256"},{"name":"fee","type":"uint256"},{"name":"admin_fee","type":"uint256"},{"name":"oracle","type":"address"},{"name":"mp_idx","type":"uint256"},{"name":"loan_discount","type":"uint256"},{"name":"liquidation_discount","type":"uint256"},{"name":"debt_ceiling","type":"uint256"}],"outputs":[{"name":"","type":"address[2]"}]},{"stateMutability":"nonpayable","type":"function","name":"set_global_market_debt_ceiling","inputs":[{"name":"debt_ceiling","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_implementations","inputs":[{"name":"A","type":"uint256"},{"name":"market","type":"address"},{"name":"amm","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"add_market_hook","inputs":[{"name":"market","type":"address"},{"name":"hook","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"remove_market_hook","inputs":[{"name":"market","type":"address"},{"name":"hook","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"add_new_monetary_policy","inputs":[{"name":"monetary_policy","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"change_existing_monetary_policy","inputs":[{"name":"monetary_policy","type":"address"},{"name":"mp_idx","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"change_market_monetary_policy","inputs":[{"name":"market","type":"address"},{"name":"mp_idx","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_peg_keeper_regulator","inputs":[{"name":"regulator","type":"address"},{"name":"with_migration","type":"bool"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_protocol_enabled","inputs":[{"name":"is_enabled","type":"bool"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"setDelegationEnabled","inputs":[{"name":"is_enabled","type":"bool"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"STABLECOIN","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"CORE_OWNER","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"peg_keeper_regulator","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"markets","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"collaterals","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"market_contracts","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"tuple","components":[{"name":"collateral","type":"address"},{"name":"amm","type":"address"},{"name":"mp_idx","type":"uint256"}]}]},{"stateMutability":"view","type":"function","name":"monetary_policies","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"n_monetary_policies","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"global_market_debt_ceiling","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"total_debt","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"minted","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"redeemed","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"isApprovedDelegate","inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"isDelegationEnabled","inputs":[],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"is_protocol_enabled","inputs":[],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"total_hook_debt","inputs":[],"outputs":[{"name":"","type":"uint256"}]}]

Deployed Bytecode

0x60003560e01c60026034820660011b61549c01601e39600051565b6393a39776811861431d573461549757602061550460403960206040f361431d565b63da5892fc811861005a573461549757602061552460403960206040f35b63b12d5460811861431d57602436103417615497576000606052610ed55661431d565b63cd15bf4c811861009957346154975760015460405260206040f35b634f02c420811861431d573461549757620201095460405260206040f361431d565b63b1283e77811861431d5760243610341761549757600435600254811015615497576003015460405260206040f361431d565b6324c1173b8118610121576024361034176154975760043562010003548110156154975762010004015460405260206040f35b632ba0840f811861431d57608436103417615497577f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610540526103585661431d565b63822b7b09811861431d57602436103417615497576004358060a01c6154975760405262020005604051602052600052604060002080546060526001810154608052600281015460a0525060606060f361431d565b63762e7b9281186101e8576024361034176154975760043560ff81116154975762020006015460405260206040f35b631ac186a68118610206573461549757620201115460405260206040f35b6356021742811861431d57604436103417615497576004358060a01c615497576040526024358060a01c6154975760605262020110604051602052600052604060002080606051602052600052604060002090505460805260206080f361431d565b63d9049c028118610286573461549757620201065460405260206040f35b63496763ce811861431d57602436103417615497576102a361527c565b60043562020107557fa9c9963960181d6ed0ed8fe32c3d0085f8a7f15be99918300892a20b1c5d7ae660043560e052602060e0a10061431d565b634faf4b4881186102fb573461549757620201075460405260206040f35b63a4639128811861431d5734615497576202010c5460405260206040f361431d565b6331dc3ca8811861033b573461549757620201085460405260206040f35b63aa5ff3c0811861431d5760a43610341761549757608435610540525b6004358060a01c61549757610500526024358060a01c61549757610520526000546002146154975760026000556044351561039457600161039a565b60643515155b61040457600f610560527f44464d3a43204e6f206368616e676500000000000000000000000000000000006105805261056050610560518061058001601f826000031636823750506308c379a061052052602061054052601f19601f61056051011660440161053cfd5b61040c614a5f565b6105005160405261041b614ac7565b6105205160405261042d6105c0614336565b6105c080516105605260208101516105805260408101516105a05250610520516107005260026107205263f9c1d1816105e45260046105005161060452610520516106245260406044610644376080016105e0526105e0602081510180610740828460045afa5050506064356040526104a76106a061496d565b6106a0805161086052602081015161088052506101a06101806101a061070060045afa506104d66106e0614d60565b6106e051606435808201828112600083121861549757905090506105c052610520516381bfcbe7610600526105005161062052604435610640526105c0516106605261054051610680526020610600608461061c6000855af161053e573d600060003e3d6000fd5b60203d10615497576106009050516105e05262020108546040526105e05160605261056a6106206148cf565b6106205161060052610600516202010855606435156106e1576064357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8113156105b457806105c3565b80600003811461549757806000035b905060008112615497576106205260016064351215610659576202010a546106205180820182811061549757905090506202010a556020615504600039600051639dc29fac61064052336106605261062051610680526020610640604461065c6000855af1610637573d600060003e3d6000fd5b60203d1061549757610640518060011c615497576106a0526106a050506106e1565b61060051604052610668615087565b6202010954610620518082018281106154975790509050620201095560206155046000396000516340c10f1961064052336106605261062051610680526020610640604461065c6000855af16106c3573d600060003e3d6000fd5b60203d1061549757610640518060011c615497576106a0526106a050505b60443515610788576044357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81131561071a5780610729565b80600003811461549757806000035b905060008112615497576106205260016044351215610767573360405261056051606052610580516080526106205160a05261078861518f56610788565b3360405261056051606052610580516080526106205160a052610788615010565b61052051604052610580516060526105a0516080526107a56150f4565b3361050051610520517f79be6dfcb3a3568b21afc806c66bcd67098197716d17923c3189da0c7973f826604435610620526105c051610640526040610620a460036000550061431d565b63e231bff0811861080d5734615497576202010a5460405260206040f35b6334bc68d0811861089057604436103417615497576024356060525b6004358060a01c6154975760405262020004604051602052600052604060002054606051106108605760006080526020608061088e565b6202000460405160205260005260406000206060518154811015615497576001820101905054608052602060805bf35b63c1342574811861431d5760843610341761549757606435610540525b6004358060a01c61549757610500526024358060a01c6154975761052052600054600214615497576002600055670de0b6b3a7640000610540511115610953576013610560527f44464d3a43206672616320746f6f2068696768000000000000000000000000006105805261056050610560518061058001601f826000031636823750506308c379a061052052602061054052601f19601f61056051011660440161053cfd5b610500516040526109656105c0614336565b6105c080516105605260208101516105805260408101516105a052506080366105c0376105005163c134257461064052336106605261052051610680526044356106a052610540516106c0526080610640608461065c6000855af16109cf573d600060003e3d6000fd5b60803d1061549757610640905080516105c05260208101516105e052604081018051610600526020810151610620525050610500516107805260086107a052637e7e3db96106645260043361068452610500516106a452610520516106c4526105e0516106e452608001610660526106606020815101806107c0828460045afa5050506105e051604052610a6461072061486f565b61072080516108e052602081015161090052506101a06101806101a061078060045afa50610a93610760614d60565b61076051610640526105e05160405261064051606052610ab46106606148cf565b610660516105e0526202010a546105e05180820182811061549757905090506202010a5562020108546040526105c051606052610af26106606148cf565b610660516202010855610600516105e05180828118828410021890509050610660526106605115610b7d576020615504600039600051639dc29fac61068052610580516106a052610660516106c0526020610680604461069c6000855af1610b5f573d600060003e3d6000fd5b60203d1061549757610680518060011c615497576106e0526106e050505b610600516105e05111610c06576105e051610600511115610c705760206155046000396000516323b872dd61068052610580516106a052336106c0526105e05161060051036106e0526020610680606461069c6000855af1610be4573d600060003e3d6000fd5b60203d1061549757610680518060011c61549757610700526107005050610c70565b610600516105e05103610680526020615504600039600051639dc29fac6106a052336106c052610680516106e05260206106a060446106bc6000855af1610c52573d600060003e3d6000fd5b60203d10615497576106a0518060011c615497576107005261070050505b6106205115610c9a573360405261056051606052610580516080526106205160a052610c9a61518f565b61050051604052610580516060526105a051608052610cb76150f4565b6105205133610500517f9ef0a399defbe09357ef7431cb1cab06dd5ede64767faa82a286b5cbda5eeaf56106205161068052610600516106a0526105e0516106c0526060610680a4610600518060ff1c615497576105e0518060ff1c615497578082038281136000831218615497579050905061068052610620516106a05260406106806003600055f361431d565b631930e825811861431d57604436103417615497576004358060a01c615497576040526024358060a01c615497576060526202010b604051602052600052604060002080606051602052600052604060002090505460805260206080f361431d565b63d2c642f28118610dc65734615497576202010d5460405260206040f35b637027745e811861431d57602436103417615497576004358060a01c6154975760405262020004604051602052600052604060002080541561549757600060018201019050546060526020620200056060516020526000526040600020600181019050546386fc88d3608052602060806004609c845afa610e4c573d600060003e3d6000fd5b60203d106154975760809050f361431d565b638da5cb5b8118610eb957346154975760206020615524600039600051638da5cb5b604052602060406004605c845afa610e9d573d600060003e3d6000fd5b60203d10615497576040518060a01c6154975760805260809050f35b631539838f8118610f5857604436103417615497576024356060525b6004358060a01c615497576040526202000460405160205260005260406000205460605110610f0c57600060805260206080610f56565b62020004604051602052600052604060002060605181548110156154975760018201019050546080526202000560805160205260005260406000206001810190505460a052602060a05bf35b63c0c1fe5f811861431d57604436103417615497576004358060a01c6154975760e0526024358060011c6154975761010052610f9261527c565b6001546101205260e051610120511861100b576019610140527f44464d3a4320726567756c61746f7220756e6368616e676564000000000000006101605261014050610140518061016001601f826000031636823750506308c379a061010052602061012052601f19601f61014051011660440161011cfd5b610100511561125d576000610140526000612160526101205163a788461461418052614080614180600461419c845afa61104a573d600060003e3d6000fd5b60803d1061549757614180516141800161010081511161549757805160008161010081116154975780156110a057905b8060051b6020850101518060a01c615497578160051b618240015260010181811861107a575b5050806182205250506141a0516141800161010081511161549757805160208160051b018061a240828560045afa505050506182209050805160208160051b0180610140828560045afa5050506120208101805160208160051b0180612160828560045afa5050505050600061014051610100811161549757801561117357905b8060051b610160015161418052614180516312898b1b6141a05260e0516141c052803b156154975760006141a060246141bc6000855af1611167573d600060003e3d6000fd5b50600101818118611121575b505060e05163eca6a2f6614180526040806141a052806141a0016000610140518083528060051b60008261010081116154975780156111cc57905b8060051b61016001518160051b6020880101526001018181186111ae575b50508201602001915050905081019050806141c052806141a0016000612160518083528060051b600082610100811161549757801561122557905b8060051b61218001518160051b602088010152600101818118611207575b50508201602001915050905081015050803b1561549757600061418061408461419c6000855af161125b573d600060003e3d6000fd5b505b60e0516001557f7e9723534c62b7bad673d3c8d3f03b638fb6c464fe3bf0636db4e7986ec7dce860e0516101405261010051610160526040610140a10061431d565b6356997a62811861431d57346154975760025460405260206040f361431d565b6363cd5a00811460033611161561431d573461549757620100035460405260206040f361431d565b637a520daa81186113505734615497576020806040528060400160006002548083528060051b60008262010000811161549757801561133c57905b80600301548160051b602088010152600101818118611322575b505082016020019150509050810190506040f35b631339051e811861431d57604436103417615497576004358060a01c61549757610500526024358060a01c6154975761052052600054600214615497576002600055610500516040526113a1614ac7565b610520516040526113b36105a0614336565b6105a0805161054052602081015161056052604081015161058052506080366105a0376105205163656c80956106205261050051610640526080610620602461063c6000855af1611409573d600060003e3d6000fd5b60803d1061549757610620905080516105a05260208101516105c0526040810180516105e052602081015161060052505061052051610740526004610760526390ce0765610644526004610500516106645261052051610684526105c0516106a45260600161064052610640602081510180610780828460045afa5050506105c0516040526114996106e061486f565b6106e080516108a05260208101516108c052506101a06101806101a061074060045afa506114c8610720614d60565b61072051610620526105c051604052610620516060526114e96106406148cf565b610640516105c0526202010a546105c05180820182811061549757905090506202010a5562020108546040526105a0516060526115276106406148cf565b6106405162020108556105e0511561159e5760206155046000396000516323b872dd61064052610560516106605233610680526105e0516106a0526020610640606461065c6000855af1611580573d600060003e3d6000fd5b60203d1061549757610640518060011c615497576106c0526106c050505b6020615504600039600051639dc29fac6106405233610660526105c051610680526020610640604461065c6000855af16115dd573d600060003e3d6000fd5b60203d1061549757610640518060011c615497576106a0526106a050506106005115611624573360405261054051606052610560516080526106005160a05261162461518f565b6105205160405261056051606052610580516080526116416150f4565b3361050051610520517fabba776d3d0b8a6980d7277a9d4c2b2d7d9ce50e6d0deac46dd8a52437869ed961060051610640526105e051610660526105c051610680526060610640a46105e0518060ff1c615497576105c0518060ff1c615497578082038281136000831218615497579050905061064052610600516106605260406106406003600055f361431d565b638c3be907811861173d57346154975760208060405280604001600062010003548083528060051b60008262010000811161549757801561172957905b806201000401548160051b60208801015260010181811861170d575b505082016020019150509050810190506040f35b630b59dfaf811861431d57606436103417615497576004358060a01c6154975760a0526024358060a01c6154975760c05260a051156117845760a051604052611784615206565b6202010f60a05160205260005260406000205460e05260006005905b806101005260e0516101005118611815576012610120527f44464d3a4320556e6b6e6f776e20686f6f6b00000000000000000000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b6202010f60a05160205260005260406000206101005181548110156154975760018201019050546101205260c05161012051604052611855610140614323565b61014051186118e6576004610120516040526118726101606143eb565b6101605118156118f157601e610180527f44464d3a4320486f6f6b20646f6573206e6f7420747261636b206465627400006101a0526101805061018051806101a001601f826000031636823750506308c379a061014052602061016052601f19601f61018051011660440161015cfd6118f1565b6001018181186117a0575b50506020615504600039600051639dc29fac610100523361012052604435610140526020610100604461011c6000855af1611931573d600060003e3d6000fd5b60203d1061549757610100518060011c615497576101605261016050506202011060a05160205260005260406000208060c05160205260005260406000209050805460443580820182811061549757905090508155506202011154604435808201828110615497579050905062020111556202010a5460443580820182811061549757905090506202010a550061431d565b633a92fa8d811861431d57602436103417615497576004358060a01c6154975760405260208060605262020004604051602052600052604060002081606001600082548083528060051b6000826101008111615497578015611a3d57905b806001880101548160051b602088010152600101818118611a21575b5050820160200191505090509050810190506060f361431d565b63e9d4fa128118611a7657602436103417615497576000606052610829565b63c3c854b6811861431d57604436103417615497576004358060a01c615497576040526024358060011c615497576060526060516202010b336020526000526040600020806040516020526000526040600020905055604051337fe259956d1d8c3e1bf78e7ed5737e2520a196a6e9e4b46474a73c00db884dbb5c60605160805260206080a30061431d565b636b35340a8118611b4157602436103417615497576004358060a01c615497576040526202000560405160205260005260406000205460605260206060f35b63e39001ce811861431d57604436103417615497576004358060a01c61549757610180526024358060a01c615497576101a052611b7c61527c565b6101805115611b945761018051604052611b94615206565b6202010f610180516020526000526040600020546101c05260006005905b806101e0526101c0516101e05118611c2a576012610200527f44464d3a4320556e6b6e6f776e20686f6f6b00000000000000000000000000006102205261020050610200518061022001601f826000031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b6101a0516202010f6101805160205260005260406000206101e0518154811015615497576001820101905054604052611c64610200614323565b6102005114611c7257611cee565b6202010f61018051602052600052604060002060018154801561549757038082558060018301019050905054610200526101c051600181038181116154975790506101e0511015611cf957610200516202010f6101805160205260005260406000206101e0518154811015615497576001820101905055611cf9565b600101818118611bb2575b505062020110610180516020526000526040600020806101a05160205260005260406000209050546101e0526101e05115611d7d57610180516080526101a05160a0526101e0518060ff1c615497577f800000000000000000000000000000000000000000000000000000000000000081146154975760000360c052611d7d614bbb565b6101a051610180517fd2ba1addacfcbcbc23a57b995978f1a0ef460e30f66abcadb6c70cc5c4154bd66101e051610200526020610200a30061431d565b632538c315811861431d57606436103417615497576004358060a01c61549757604052620201075460605262020108546040516359e7137f60a052602060a0600460bc845afa611e0f573d600060003e3d6000fd5b60203d106154975760a0905051808201828110615497579050905060805260605160805110611e4657600060a052602060a0611eb5565b606051608051808203828111615497579050905060a052604051639a49719660e0526040602461010037602060e0604460fc845afa611e8a573d600060003e3d6000fd5b60203d106154975760e090505160c05260a05160c0518082811882841002189050905060e052602060e05bf361431d565b63d3a76351811861431d57602436103417615497576202010e6004356020526000526040600020805460405260018101546060525060406040f361431d565b63248fed2b81186120cc57602436103417615497576004358060a01c615497576060526202010f6060516020526000526040600020805460208160051b01600081601f0160051c60058111615497578015611f6857905b808501548160051b60800152600101818118611f51575b505050505060006101205260006080516004811161549757801561206057905b8060051b60a001516104405260c0366104603761044051604052611fad610520614323565b61052051610460526007610440511660011c6104805260006004905b8061052052600861044051610520511c1615611ff657600161052051600381116154975760051b6104a001525b600101818118611fc957505061012051600381116154975760c0810261014001610460518152610480516020820152604081016104a05181526104c05160208201526104e05160408201526105005160608201525050600181016101205250600101818118611f88575b505060208061044052806104400160006101205180835260c08102600082600481116154975780156120b757905b60c081026101400160c08202602088010160c08160c08460045afa50505060010181811861208e575b50508201602001915050905081019050610440f35b635f88653b811861431d5761012436103417615497576004358060a01c6154975760e0526084358060a01c615497576101005261210761527c565b67016345785d8a0000604435111561217d576012610120527f44464d3a432046656520746f6f206869676800000000000000000000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b620f424060443510156121ee576011610120527f44464d3a432046656520746f6f206c6f770000000000000000000000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b670de0b6b3a76400006064351115612264576018610120527f44464d3a432041646d696e2066656520746f6f206869676800000000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b662386f26fc1000060e43510156122d957601a610120527f44464d3a43206c697120646973636f756e7420746f6f206c6f770000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b6706f05b59d3b2000060c435111561234f57601c610120527f44464d3a43204c6f616e20646973636f756e7420746f6f2068696768000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b60e43560c435116123be576020610120527f44464d3a43206c6f616e20646973636f756e743c6c697120646973636f756e746101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b620201065460a4351061242f576014610120527f44464d3a4320696e76616c6964206d705f6964780000000000000000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b6101005163a035b1fe610140526020610140600461015c845afa612458573d600060003e3d6000fd5b60203d106154975761014090505161012052610120516124d857600c610140527f44464d3a432070203d3d203000000000000000000000000000000000000000006101605261014050610140518061016001601f826000031636823750506308c379a061010052602061012052601f19601f61014051011660440161011cfd5b610120516101005163ceb7f759610140526020610140600461015c6000855af1612507573d600060003e3d6000fd5b60203d10615497576101409050511815612581576012610180527f44464d3a43207020213d2070726963655f7700000000000000000000000000006101a0526101805061018051806101a001601f826000031636823750506308c379a061014052602061016052601f19601f61018051011660440161015cfd5b6202010e6024356020526000526040600020805461014052600181015461016052506101405161261157601d610180527f44464d3a43204e6f20696d706c656d656e746174696f6e20666f7220410000006101a0526101805061018051806101a001601f826000031636823750506308c379a061014052602061016052601f19601f61018051011660440161015cfd5b4660b01b60e05160101b80820182811061549757905090506202000460e0516020526000526040600020548082018281106154975790509050610180527f602d3d8160093d39f3363d3d373d3d3d363d73000000000000000000000000006101c0526101605160601b6101d3527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006101e75261018051600052602060002060366101c06000f58015615497576101a0527f602d3d8160093d39f3363d3d373d3d3d363d73000000000000000000000000006101e0526101405160601b6101f3527f5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000610207526101805160081b600052602060002060366101e06000f58015615497576101c0526101a05163d13f90b46101e0526101c0516102005260e05161022052610104356102405260c4356102605260e43561028052803b156154975760006101e060a46101fc6000855af161278e573d600060003e3d6000fd5b506101c05163728cdbca6101e0526101a05161020052610100516102205260e0516102405261012051610260526040604461028037803b156154975760006101e060c46101fc6000855af16127e8573d600060003e3d6000fd5b5060025461ffff8111615497576101a051816003015560018101600255506202000460e05160205260005260406000205461284057620100035461ffff81116154975760e05181620100040155600181016201000355505b6202000460e0516020526000526040600020805460ff8111615497576101a051816001840101556001810182555050620200056101a051602052600052604060002060e05181556101c051600182015560a43560028201555060e0517f11bde9719002acc56e38889ee650bb993138c9e08678d8ba4ddd743825e00d416101a0516101e0526101c0516102005260a4356102205260606101e0a26101a0516101e0526101c0516102005260406101e0f361431d565b632543eb32811861431d57602436103417615497576004358060a01c6154975760405262020005604051602052600052604060002080546060526001810154608052600281015460a0525060605161295557600060c052602060c061296e565b60a05160ff81116154975762020006015460c052602060c05bf361431d565b6375d2ed08811861431d57346154975760015460405260405161299f576000606052602060606129d3565b602060405163305b4d6c606052602060606004607c845afa6129c6573d600060003e3d6000fd5b60203d1061549757606090505bf361431d565b6369ab47b88118612a3057346154975762020108546202010a548082018281106154975790509050620201095480820382811161549757905090506202011154808203828111615497579050905060405260206040f35b635da5f18c811861431d57602436103417615497576004358060011c615497576101605261016051604052612a6361532a565b610160516202010d557f2b5d179d82230ba43503598d00077c0cc165d285bbdf1e763ee4584b9e49561b3361018052610160516101a0526040610180a10061431d565b635b7aaef1811861431d57604436103417615497576004358060a01c615497576104a0526024358060a01c615497576104c0526104c051604052612aeb610500614336565b610500602081019050516104e0526104e05163544fb5c1610540526104a051610560526040610540602461055c845afa612b2a573d600060003e3d6000fd5b60403d10615497576105409050805161050052602081015161052052506104c051639b6c56ec610560526104a051610580526020610560602461057c845afa612b78573d600060003e3d6000fd5b60203d1061549757610560905051610540526104c0516106805260046106a052631baf02036105845260046104a0516105a4526104c0516105c452610540516105e452606001610580526105806020815101806106c0828460045afa50505061054051604052612be961062061486f565b61062080516107e052602081015161080052506101a06101006101a061068060045afa50612c186106606144e4565b61066051610560526105405160405261056051606052612c396105806148cf565b6105805161054052610500518060ff1c61549757610540518060ff1c615497578082038281136000831218615497579050905061058052610520516105a0526040610580f361431d565b632f4b9e4b811861431d57608436103417615497576004358060a01c615497576104a0526024358060a01c615497576104c05260206104c0516106005260016106205263d0ab1c8a6104e45260046104a051610504526104c0516105245260406044610544376080016104e0526104e0602081510180610640828460045afa505050606435604052612d166105a061486f565b6105a0805161076052602081015161078052506101a06101006101a061060060045afa50612d456105e06144e4565b6105e0f361431d565b6305d9d3a2811861431d57608436103417615497576004358060a01c615497576104a0526024358060a01c615497576104c05260206104c05161060052600261062052632406a3506104e45260046104a051610504526104c0516105245260406044610544376080016104e0526104e0602081510180610640828460045afa505050606435604052612de16105a061496d565b6105a0805161076052602081015161078052506101a06101006101a061060060045afa50612e106105e06144e4565b6105e0f361431d565b635af8e5fc8118612f2457604436103417615497576004358060a01c615497576104a0526024358060a01c615497576104c0526104c051639b6c56ec610500526104a051610520526020610500602461051c845afa612e7d573d600060003e3d6000fd5b60203d10615497576105009050516104e05260206104c05161060052600461062052631baf02036105045260046104a051610524526104c051610544526104e0516105645260600161050052610500602081510180610640828460045afa5050506104e051604052612ef06105a061486f565b6105a0805161076052602081015161078052506101a06101006101a061060060045afa50612f1f6105e06144e4565b6105e0f35b63e6932ac8811861431d57604436103417615497576004358060a01c6154975761010052612f5061527c565b61010051604052612f5f615206565b620201065460243510612fd0576014610120527f44464d3a4320696e76616c6964206d705f6964780000000000000000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b602435620200056101005160205260005260406000206002810190505561010051604052620200056101005160205260005260406000206001810190505460605260243560805261301f6150f4565b602435610100517fe2b88e5e080a641a4620ca23c04dcb08bf9cc02097b43e0507d510e1262970a96000610120a30061431d565b63166dabef811861317557606436103417615497576004358060a01c615497576104a0526024358060a01c615497576104c0526044358060a01c615497576104e0526104c051639b6c56ec610520526104e051610540526020610520602461053c845afa6130c6573d600060003e3d6000fd5b60203d10615497576105209050516105005260206104c0516106405260086106605263f4a589746105245260046104a051610544526104c051610564526104e05161058452610500516105a45260800161052052610520602081510180610680828460045afa505050610500516040526131416105e061486f565b6105e080516107a05260208101516107c052506101a06101006101a061064060045afa506131706106206144e4565b610620f35b6326c01303811861431d5760643610341761549757670de0b6b3a7640000610540526108ad5661431d565b638930995f811861431d5760a436103417615497576004358060a01c61549757610500526024358060a01c6154975761052052600054600214615497576002600055604435156131f45760643515156131f7565b60005b613261576014610540527f44464d3a43203020636f6c6c206f7220646562740000000000000000000000006105605261054050610540518061056001601f826000031636823750506308c379a061050052602061052052601f19601f61054051011660440161051cfd5b613269614a5f565b61050051604052613278614ac7565b6105205160405261328a6105a0614336565b6105a080516105405260208101516105605260408101516105805250610520516106e052600161070052632f7e21a46105c4526004610500516105e452610520516106045260406044610624376080016105c0526105c0602081510180610720828460045afa50505060643560405261330461068061486f565b610680805161084052602081015161086052506101a06101806101a06106e060045afa506133336106c0614d60565b6106c0516105a0526064356040526105a0516060526133536105e06148cf565b6105e0516105c05233604052610540516060526105605160805260443560a05261337b615010565b6105205163d9a39df8610600526105005161062052604435610640526105c05161066052608435610680526020610600608461061c6000855af16133c4573d600060003e3d6000fd5b60203d10615497576106009050516105e05262020108546105e05180820182811061549757905090506106005261060051604052613400615087565b61060051620201085562020109546064358082018281106154975790509050620201095560206155046000396000516340c10f19610620523361064052606435610660526020610620604461063c6000855af1613462573d600060003e3d6000fd5b60203d1061549757610620518060011c6154975761068052610680505061052051604052610560516060526105805160805261349c6150f4565b3361050051610520517fbf2742c8e657897c9f047c065e83679fdea6e8bf1a460402c3c922f800b74bf1604435610620526105c051610640526040610620a460036000550061431d565b636280c9ab811861431d576044361034176154975760043560040160ff81351161549757803560008160ff811161549757801561354557905b8060051b6020850101358060a01c615497578160051b610180015260010181811861351f575b505080610160525050600054600214615497576002600055613565614a5f565b602061552460003960005163b3f00674612180526020612180600461219c845afa613595573d600060003e3d6000fd5b60203d1061549757612180518060a01c615497576121c0526121c090505161216052614000366121803760006101605160ff81116154975780156137a357905b8060051b610180015161618052616180516040526135f4616200614336565b61620080516161a05260208101516161c05260408101516161e052506060366162003761618051631e0cfcef616260526060616260600461627c6000855af1613642573d600060003e3d6000fd5b60603d10615497576162609050805161620052602081018051616220526020810151616240525050612180516162005180820182811061549757905090506121805261622051156136f55760206155046000396000516323b872dd616260526161c05161628052612160516162a052616220516162c0526020616260606461627c6000855af16136d7573d600060003e3d6000fd5b60203d1061549757616260518060011c615497576162e0526162e050505b616240511561372257612160516040526161a0516060526161c0516080526162405160a05261372261518f565b616180517f04dd27d55b92d68e556c87c41371d3c5ff554a0abd8ecb5cfa8ac7f917c94f3e616240516162605261622051616280526040616260a26161c0516121a05160fe81116154975760051b6121c001526161e0516121a05160fe81116154975760051b6141a0015260016121a051016121a0526001018181186135d5575b505062020108546121805180820182811061549757905090506161805261618051620201085560006161a05262020109546161c0526202010a546161e052616180516161e051808201828110615497579050905062020111548082038281116154975790509050616200526161c051616200511115613892576162005162020109556161c05161620051036161a05260206155046000396000516340c10f196162205261216051616240526161a051616260526020616220604461623c6000855af1613874573d600060003e3d6000fd5b60203d1061549757616220518060011c615497576162805261628050505b60006121a05260006101605160ff811161549757801561390e57905b8060051b610180015161622052616220516040526121a05160fe81116154975760051b6121c001516060526121a05160fe81116154975760051b6141a001516080526138f86150f4565b60016121a051016121a0526001018181186138ae575b50507f1ac56d7e866e3f5ea9aa92aa11758ead39a0a5f013f3fefb0f47cb9d008edd276161c051616220526161e0516162405261618051616260526161a051616280526080616220a160206161a06003600055f361431d565b63a8d706ed811861431d57606436103417615497576024358060a01c6154975760e0526044358060a01c61549757610100526139a161527c565b600260043510156139b35760006139bc565b61271060043511155b613a24576016610120527f44464d3a432041206f75747369646520626f756e6473000000000000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b60e0516101005118613aa1576101005115613c6a57601e610120527f44464d3a43206d61746368696e6720696d706c656d656e746174696f6e7300006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd613c6a565b6101005115613ab45760e0511515613ab7565b60005b613b1f57601a610120527f44464d3a4320656d70747920696d706c656d656e746174696f6e0000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b60043560e05163f446c1d0610120526020610120600461013c845afa613b4a573d600060003e3d6000fd5b60203d10615497576101209050511815613bc4576018610160527f44464d3a4320696e636f7272656374206d61726b6574204100000000000000006101805261016050610160518061018001601f826000031636823750506308c379a061012052602061014052601f19601f61016051011660440161013cfd5b6004356101005163f446c1d0610120526020610120600461013c845afa613bf0573d600060003e3d6000fd5b60203d10615497576101209050511815613c6a576015610160527f44464d3a4320696e636f727265637420616d6d204100000000000000000000006101805261016050610160518061018001601f826000031636823750506308c379a061012052602061014052601f19601f61016051011660440161013cfd5b6202010e600435602052600052604060002061010051815560e0516001820155506004357fb55605b8d8e835ca6641329db445749b15ad50629b4ee079e7c8e88ea186a426610100516101205260e051610140526040610120a20061431d565b6332edb110811861431d57604436103417615497576004358060a01c6154975760e0526024358060a01c6154975761010052613d0461527c565b60e05115613d1a5760e051604052613d1a615206565b6202010f60e0516020526000526040600020805460208160051b01600081601f0160051c60058111615497578015613d6657905b808501548160051b6101200152600101818118613d4e575b50505050506003610120511115613ddd5760206101c0527f44464d3a43204d6178696d756d20686f6f6b20636f756e7420726561636865646101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b60006101205160048111615497578015613e9057905b8060051b61014001516101c052610100516101c051604052613e166101e0614323565b6101e05118613e85576018610200527f44464d3a4320486f6f6b20616c726561647920616464656400000000000000006102205261020050610200518061022001601f826000031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b600101818118613df3575b5050610100516375fec5946102605260a0610260600461027c845afa613ebb573d600060003e3d6000fd5b60a03d10615497576102605161032052610280518060011c61549757610340526102a0518060011c61549757610360526102c0518060011c61549757610380526102e0518060011c615497576103a052610320905080516101c0526020810180516101e052602081015161020052604081015161022052606081015161024052505060026101c0511115613faf576017610260527f44464d3a4320496e76616c696420686f6f6b20747970650000000000000000006102805261026050610260518061028001601f826000031636823750506308c379a061022052602061024052601f19601f61026051011660440161023cfd5b60016101c0511b6102605260006004905b806102805261028051600381116154975760051b6101e00151156140095761026051600161028051600381018181106154975790501b8082018281106154975790509050610260525b600101818118613fc05750506102605160031c61408657601b610280527f44464d3a43204e6f2061637469766520686f6f6b20706f696e747300000000006102a0526102805061028051806102a001601f826000031636823750506308c379a061024052602061026052601f19601f61028051011660440161025cfd5b610260516101005160601b8082018281106154975790509050610260526202010f60e051602052600052604060002080546003811161549757610260518160018401015560018101825550506101005160e0517f87e627cd8c8921af9587fe2e6d32b3cdaa8d64ede0faf1f3b5b67920e03d33406101c051610280526101e0516102a052610200516102c052610220516102e052610240516103005260a0610280a30061431d565b633e100c7e811861431d57602436103417615497576004358060a01c6154975760e05261415961527c565b62020106546101005260e0516101005160ff81116154975762020006015561010051600181018181106154975790506202010655610100517fc52c1bf04d9533f4ddbbb056f87ebeb235891134e87667bf3ff3327ce15886e860e051610120526020610120a20061431d565b63e1eacc8f811861431d57604436103417615497576004358060a01c6154975760e0526141f061527c565b620201065460243510614260576014610100527f44464d3a4320696e76616c6964206d705f6964780000000000000000000000006101205261010050610100518061012001601f826000031636823750506308c379a060c052602060e052601f19601f61010051011660440160dcfd5b60e05160243560ff8111615497576202000601556024357f360fb1b952a743afe4c3396fc3229723a4ebd3cb2a3cefa111bb00bb0ff7589860e051610100526020610100a20061431d565b63f28699fa811861431d57602436103417615497576004358060011c6154975761016052610160516040526142de61532a565b610160516202010c557ff8d26d1a3a211bb38503963aa0898e2a241f291063df5c514d4ed06ae14b97ee3361018052610160516101a0526040610180a1005b60006000fd5b60405160601c8060a01c61549757815250565b62020005604051602052600052604060002080546060526001810154608052600281015460a052506060516143c257601460c0527f44464d3a4320496e76616c6964206d61726b657400000000000000000000000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b6060518152608051602082015260a051604082015250565b60605160031b604051161515815250565b6007604051168060031c61549757815250565b606051604051126144155760805160405113614418565b60015b156144e25760a05161448557601e60c0527f44464d3a4320486f6f6b2063617573656420696e76616c69642064656274000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd6144e2565b601c60c0527f44464d3a4320686f6f6b2073756d206f7574206f6620626f756e64730000000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b565b60006102a052610100516102e05260006103005260006002905b8060051b6102e001516102c0526202010f6102c0516020526000526040600020805460208160051b01600081601f0160051c6005811161549757801561455857905b808501548160051b6103200152600101818118614540575b50505050506103205161456a5761482f565b6000610320516004811161549757801561482c57905b8060051b61034001516103c0526103c051604052610120516060526145a66103e06143da565b6103e0516145b357614821565b6103c0516040526145c5610400614323565b610400516103e0526103e0515a610140506020610440610140516101608585fa905090506145f8573d600060003e3d6000fd5b3d602081183d6020100218610420526104206020810151815160200360031b1d9050610400526104005161462b57614821565b6103c05160405261463d6104406143eb565b6104405161042052600161042051186146b657601d610440527f44464d3a4320486f6f6b2063616e6e6f742061646a75737420646562740000006104605261044050610440518061046001601f826000031636823750506308c379a061040052602061042052601f19601f61044051011660440161041cfd5b600261042051186146e55761040051604052600060605261028051608052600060a0526148016143fe56614801565b610400516040526102605160605261028051608052600060a0526147076143fe565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610400511361480157620201106102c0516020526000526040600020806103e051602052600052604060002090505461044052610400517f80000000000000000000000000000000000000000000000000000000000000008114615497576000036000811261549757610440511015614801576019610460527f44464d3a4320486f6f6b206465627420756e646572666c6f77000000000000006104805261046050610460518061048001601f826000031636823750506308c379a061042052602061044052601f19601f61046051011660440161043cfd5b6102a05161040051808201828112600083121861549757905090506102a0525b600101818118614580575b50505b6001018181186144fe5750506102a05115614866576102a0516040526102605160605261028051608052600160a0526148666143fe565b6102a051815250565b6040518060ff1c615497577f800000000000000000000000000000000000000000000000000000000000000081146154975760000381527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602082015250565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6060511315614921576040516060516000811261549757808201828110615497579050905081525061496b5661496b565b6040516060517f8000000000000000000000000000000000000000000000000000000000000000811461549757600003600081126154975780820382811161549757905090508152505b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff604051136149f1577f800000000000000000000000000000000000000000000000000000000000000081526040517f8000000000000000000000000000000000000000000000000000000000000000811461549757600003602082015250614a5d565b600160405112614a56576040517f800000000000000000000000000000000000000000000000000000000000000081146154975760000381527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602082015250614a5d565b6040368237505b565b6202010d54614ac55760206040527f44464d3a432050726f746f636f6c2070617573652c20636c6f7365206f6e6c7960605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b565b6040513314614bb9576202010c54614b365760196060527f44464d3a432044656c65676174696f6e2064697361626c65640000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6202010b604051602052600052604060002080336020526000526040600020905054614bb957601b6060527f44464d3a432044656c6567617465206e6f7420617070726f766564000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b565b6202011060805160205260005260406000208060a051602052600052604060002090505460e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60c05113614cac5760c0517f8000000000000000000000000000000000000000000000000000000000000000811461549757600003600081126154975760e0511015614cac576019610100527f44464d3a4320486f6f6b206465627420756e646572666c6f77000000000000006101205261010050610100518061012001601f826000031636823750506308c379a060c052602060e052601f19601f61010051011660440160dcfd5b60e05160405260c051606052614cc36101006148cf565b6101005160e052620201115460405260c051606052614ce36101206148cf565b610120516101005260e0516202011060805160205260005260406000208060a051602052600052604060002090505561010051620201115560a0516080517fce64682be365129d68e82326ad253f548f1f36f36772ea07298122b16c4fbdb260c0516101205260e0516101405261010051610160526060610120a3565b600061032052610180516103605260006103805260006002905b8060051b6103600151610340526202010f610340516020526000526040600020805460208160051b01600081601f0160051c60058111615497578015614dd457905b808501548160051b6103a00152600101818118614dbc575b50505050506103a051614de657614fd0565b60006103a05160048111615497578015614fcd57905b8060051b6103c0015161044052610440516040526101a051606052614e226104606143da565b61046051614e2f57614fc2565b61044051604052614e41610480614323565b6104805161046052610460515a6101c05060206104c06101c0516101e060008686f190509050614e76573d600060003e3d6000fd5b3d602081183d60201002186104a0526104a06020810151815160200360031b1d90506104805261048051614ea957614fc2565b61044051604052614ebb6104c06143eb565b6104c0516104a05260016104a05118614f3457601d6104c0527f44464d3a4320486f6f6b2063616e6e6f742061646a75737420646562740000006104e0526104c0506104c051806104e001601f826000031636823750506308c379a06104805260206104a052601f19601f6104c051011660440161049cfd5b60026104a05118614f635761048051604052600060605261030051608052600060a052614fa26143fe56614fa2565b610480516040526102e05160605261030051608052600060a052614f856143fe565b610340516080526104605160a0526104805160c052614fa2614bbb565b610320516104805180820182811260008312186154975790509050610320525b600101818118614dfc575b50505b600101818118614d7a575050610320511561500757610320516040526102e05160605261030051608052600160a0526150076143fe565b61032051815250565b6060516323b872dd60c05260405160e0526080516101005260a05161012052602060c0606460dc6000855af161504b573d600060003e3d6000fd5b3d61506257803b156154975760016101405261507a565b60203d106154975760c0518060011c61549757610140525b6101409050511561549757565b620201075460405111156150f25760196060527f44464d3a4320676c6f62616c2064656274206365696c696e670000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b565b60805160ff81116154975762020006015463bdb09f2e60c05260405160e052602060c0602460dc6000855af161512f573d600060003e3d6000fd5b60203d106154975760c0905051640a3c2abcef818118640a3c2abcef83100218905060a05260605163d4387a9960c05260a05160e052602060c0602460dc6000855af1615181573d600060003e3d6000fd5b60203d106154975760c05050565b6060516323b872dd60c05260805160e0526040516101005260a05161012052602060c0606460dc6000855af16151ca573d600060003e3d6000fd5b3d6151e157803b15615497576001610140526151f9565b60203d106154975760c0518060011c61549757610140525b6101409050511561549757565b6202000560405160205260005260406000205461527a5760146060527f44464d3a4320496e76616c6964206d61726b657400000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b565b6020615524600039600051638da5cb5b604052602060406004605c845afa6152a9573d600060003e3d6000fd5b60203d10615497576040518060a01c61549757608052608090505133181561532857601060a0527f44464d3a43204f6e6c79206f776e65720000000000000000000000000000000060c05260a05060a0518060c001601f826000031636823750506308c379a06060526020608052601f19601f60a0510116604401607cfd5b565b6020615524600039600051638da5cb5b606052602060606004607c845afa615357573d600060003e3d6000fd5b60203d10615497576060518060a01c6154975760a05260a0905051331461549557602061552460003960005163452a932060c052602060c0600460dc845afa6153a5573d600060003e3d6000fd5b60203d106154975760c0518060a01c61549757610100526101009050513318615438576040511561549557601f610120527f44464d3a4320477561726469616e2063616e206f6e6c792064697361626c65006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd615495565b601b60c0527f44464d3a43204e6f74206f776e6572206f7220677561726469616e000000000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b565b600080fd031d19c30da816d03cca1dba412e41c5431d431d026831a002dd431d01b91efa12bf431d12e70e5e003c431d42ab00ee29d939672d4e2c832974431d1a5734e6431d1ebb431d431d431d431d129f431d2e192aa61b02431d07ef0d46001a3053007d016428f500bb00000000000000000000000069420f9e38a4e60a62224c489be4bf7a94402496000000000000000000000000c0deb055a11fd0801040de91a1fac500dc577f00

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

OVERVIEW

Main controller used to open, adjust, close and liquidate CDP's within Defi.Money

Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.