{"file_path":"curve_stablecoin/mpolicies/AggMonetaryPolicy4.vy","creation_status":"success","source_code":"#pragma version 0.4.3\n\"\"\"\n@title AggMonetaryPolicy - monetary policy based on aggregated prices for crvUSD\n@author Curve.Fi\n@license Copyright (c) Curve.Fi, 2020-2024 - all rights reserved\n@custom:kill This contract doesn't have a kill switch as halting it would brick most markets.\n    to stop it, simply set another monetary policy in all Controllers using this one.\n\"\"\"\n\n# This version uses min(last day) debt when calculating per-market rates\n# Should be used for Controllers which update borrow rate too early (not at the end of every call)\n\nfrom curve_std import ema\n\ninitializes: ema\n\n\ninterface PegKeeper:\n    def debt() -> uint256: view\n\ninterface PriceOracle:\n    def price() -> uint256: view\n    def price_w() -> uint256: nonpayable\n\ninterface ControllerFactory:\n    def total_debt() -> uint256: view\n    def debt_ceiling(_for: address) -> uint256: view\n    def n_collaterals() -> uint256: view\n    def controllers(i: uint256) -> address: view\n\ninterface Controller:\n    def total_debt() -> uint256: view\n\n\nstruct TotalDebts:\n    total_debt: uint256\n    controller_debt: uint256\n    ceiling: uint256\n\n\nevent SetAdmin:\n    admin: address\n\nevent AddPegKeeper:\n    peg_keeper: indexed(address)\n\nevent RemovePegKeeper:\n    peg_keeper: indexed(address)\n\nevent SetRate:\n    rate: uint256\n\nevent SetSigma:\n    sigma: int256\n\nevent SetTargetDebtFraction:\n    target_debt_fraction: uint256\n\nevent SetExtraConst:\n    extra_const: uint256\n\nevent SetDebtRatioEmaTime:\n    debt_ratio_ema_time: uint256\n\n\nadmin: public(address)\n\nrate0: public(uint256)\nsigma: public(int256)  # 2 * 10**16 for example\ntarget_debt_fraction: public(uint256)\nextra_const: public(uint256)\n\npeg_keepers: public(PegKeeper[1001])\nPRICE_ORACLE: public(immutable(PriceOracle))\nCONTROLLER_FACTORY: public(immutable(ControllerFactory))\n\n# Cache for controllers\nMAX_CONTROLLERS: constant(uint256) = 50000\nn_controllers: public(uint256)\ncontrollers: public(address[MAX_CONTROLLERS])\n\n\nstruct DebtCandle:\n    candle0: uint256  # earlier 1/2 day candle\n    candle1: uint256   # later 1/2 day candle\n    timestamp: uint256\n\nDEBT_CANDLE_TIME: constant(uint256) = 86400 // 2\nmin_debt_candles: public(HashMap[address, DebtCandle])\n\n\nDEBT_RATIO_EMA_ID: constant(String[4]) = \"pkr\"\n\nMAX_TARGET_DEBT_FRACTION: constant(uint256) = 10**18\nMAX_SIGMA: constant(int256) = 10**18\nMIN_SIGMA: constant(int256) = 10**14\nMAX_EXP: constant(uint256) = 1000 * 10**18\nMAX_RATE: constant(uint256) = 43959106799  # 300% APY\nTARGET_REMAINDER: constant(uint256) = 10**17  # rate is x1.9 when 10% left before ceiling\nMAX_EXTRA_CONST: constant(uint256) = MAX_RATE\n\n\n@deploy\ndef __init__(admin: address,\n             price_oracle: PriceOracle,\n             controller_factory: ControllerFactory,\n             peg_keepers: PegKeeper[5],\n             rate: uint256,\n             sigma: int256,\n             target_debt_fraction: uint256,\n             extra_const: uint256,\n             _debt_ratio_ema_time: uint256):\n    self.admin = admin\n    PRICE_ORACLE = price_oracle\n    CONTROLLER_FACTORY = controller_factory\n    for i: uint256 in range(5):\n        if peg_keepers[i].address == empty(address):\n            break\n        self.peg_keepers[i] = peg_keepers[i]\n\n    assert sigma >= MIN_SIGMA  # dev: sigma too low\n    assert sigma <= MAX_SIGMA  # dev: sigma too high\n    assert target_debt_fraction > 0  # dev: target debt fraction is zero\n    assert target_debt_fraction <= MAX_TARGET_DEBT_FRACTION  # dev: target debt fraction too high\n    assert rate <= MAX_RATE  # dev: rate too high\n    assert extra_const <= MAX_EXTRA_CONST  # dev: extra const too high\n    self.rate0 = rate\n    self.sigma = sigma\n    self.target_debt_fraction = target_debt_fraction\n    self.extra_const = extra_const\n\n    ema.__init__([ema.EMAConfig(ema_id=DEBT_RATIO_EMA_ID, initial_value=target_debt_fraction, ema_time=_debt_ratio_ema_time)])\n\n\n@external\ndef set_admin(admin: address):\n    assert msg.sender == self.admin  # dev: only admin\n    self.admin = admin\n    log SetAdmin(admin=admin)\n\n\n@external\ndef add_peg_keeper(pk: PegKeeper):\n    assert msg.sender == self.admin  # dev: only admin\n    assert pk.address != empty(address)  # dev: peg keeper is zero address\n    for i: uint256 in range(1000):\n        _pk: PegKeeper = self.peg_keepers[i]\n        assert _pk != pk, \"Already added\"\n        if _pk.address == empty(address):\n            self.peg_keepers[i] = pk\n            log AddPegKeeper(peg_keeper=pk.address)\n            break\n\n\n@external\ndef remove_peg_keeper(pk: PegKeeper):\n    assert msg.sender == self.admin  # dev: only admin\n    replaced_peg_keeper: uint256 = 10000\n    for i: uint256 in range(1001):  # 1001th element is always 0x0\n        _pk: PegKeeper = self.peg_keepers[i]\n        if _pk == pk:\n            replaced_peg_keeper = i\n            log RemovePegKeeper(peg_keeper=pk.address)\n        if _pk.address == empty(address):\n            if replaced_peg_keeper < i:\n                if replaced_peg_keeper < i - 1:\n                    self.peg_keepers[replaced_peg_keeper] = self.peg_keepers[i - 1]\n                self.peg_keepers[i - 1] = PegKeeper(empty(address))\n            break\n\n\n@internal\n@pure\ndef exp(power: int256) -> uint256:\n    if power <= -41446531673892821376:\n        return 0\n\n    if power >= 135305999368893231589:\n        # Return MAX_EXP when we are in overflow mode\n        return MAX_EXP\n\n    x: int256 = unsafe_div(unsafe_mul(power, 2**96), 10**18)\n\n    k: int256 = unsafe_div(\n        unsafe_add(\n            unsafe_div(unsafe_mul(x, 2**96), 54916777467707473351141471128),\n            2**95),\n        2**96)\n    x = unsafe_sub(x, unsafe_mul(k, 54916777467707473351141471128))\n\n    y: int256 = unsafe_add(x, 1346386616545796478920950773328)\n    y = unsafe_add(unsafe_div(unsafe_mul(y, x), 2**96), 57155421227552351082224309758442)\n    p: int256 = unsafe_sub(unsafe_add(y, x), 94201549194550492254356042504812)\n    p = unsafe_add(unsafe_div(unsafe_mul(p, y), 2**96), 28719021644029726153956944680412240)\n    p = unsafe_add(unsafe_mul(p, x), (4385272521454847904659076985693276 * 2**96))\n\n    q: int256 = x - 2855989394907223263936484059900\n    q = unsafe_add(unsafe_div(unsafe_mul(q, x), 2**96), 50020603652535783019961831881945)\n    q = unsafe_sub(unsafe_div(unsafe_mul(q, x), 2**96), 533845033583426703283633433725380)\n    q = unsafe_add(unsafe_div(unsafe_mul(q, x), 2**96), 3604857256930695427073651918091429)\n    q = unsafe_sub(unsafe_div(unsafe_mul(q, x), 2**96), 14423608567350463180887372962807573)\n    q = unsafe_add(unsafe_div(unsafe_mul(q, x), 2**96), 26449188498355588339934803723976023)\n\n    return shift(\n        unsafe_mul(convert(unsafe_div(p, q), uint256), 3822833074963236453042738258902158003155416615667),\n        unsafe_sub(k, 195))\n\n\n@internal\n@view\ndef get_total_debt(_for: address) -> (uint256, uint256):\n    n_controllers: uint256 = self.n_controllers\n    total_debt: uint256 = 0\n    debt_for: uint256 = 0\n\n    for i: uint256 in range(MAX_CONTROLLERS):\n        if i >= n_controllers:\n            break\n        controller: address = self.controllers[i]\n\n        success: bool = False\n        res: Bytes[32] = empty(Bytes[32])\n        success, res = raw_call(controller, method_id(\"total_debt()\"), max_outsize=32, is_static_call=True, revert_on_failure=False)\n        debt: uint256 = convert(res, uint256)\n        total_debt += debt\n        if controller == _for:\n            debt_for = debt\n\n    return total_debt, debt_for\n\n\n@internal\n@view\ndef read_candle(_for: address) -> uint256:\n    out: uint256 = 0\n    candle: DebtCandle = self.min_debt_candles[_for]\n\n    if block.timestamp < candle.timestamp // DEBT_CANDLE_TIME * DEBT_CANDLE_TIME + DEBT_CANDLE_TIME:\n        if candle.candle0 > 0:\n            out = min(candle.candle0, candle.candle1)\n        else:\n            out = candle.candle1\n    elif block.timestamp < candle.timestamp // DEBT_CANDLE_TIME * DEBT_CANDLE_TIME + DEBT_CANDLE_TIME * 2:\n        out = candle.candle1\n\n    return out\n\n\n@internal\ndef save_candle(_for: address, _value: uint256):\n    candle: DebtCandle = self.min_debt_candles[_for]\n\n    if candle.timestamp == 0 and _value == 0:\n        # This record did not exist before, and value is zero -> not recording anything\n        return\n\n    if block.timestamp >= candle.timestamp // DEBT_CANDLE_TIME * DEBT_CANDLE_TIME + DEBT_CANDLE_TIME:\n        if block.timestamp < candle.timestamp // DEBT_CANDLE_TIME * DEBT_CANDLE_TIME + DEBT_CANDLE_TIME * 2:\n            candle.candle0 = candle.candle1\n            candle.candle1 = _value\n        else:\n            candle.candle0 = _value\n            candle.candle1 = _value\n    else:\n        candle.candle1 = min(candle.candle1, _value)\n\n    candle.timestamp = block.timestamp\n    self.min_debt_candles[_for] = candle\n\n\n@internal\n@view\ndef read_debt(_for: address, ro: bool) -> (uint256, uint256):\n    debt_total: uint256 = self.read_candle(empty(address))\n    debt_for: uint256 = self.read_candle(_for)\n    fresh_total: uint256 = 0\n    fresh_for: uint256 = 0\n\n    if ro:\n        fresh_total, fresh_for = self.get_total_debt(_for)\n        if debt_total > 0:\n            debt_total = min(debt_total, fresh_total)\n        else:\n            debt_total = fresh_total\n        if debt_for > 0:\n            debt_for = min(debt_for, fresh_for)\n        else:\n            debt_for = fresh_for\n\n    else:\n        if debt_total == 0 or debt_for == 0:\n            fresh_total, fresh_for = self.get_total_debt(_for)\n            if debt_total == 0:\n                debt_total = fresh_total\n            if debt_for == 0:\n                debt_for = fresh_for\n\n    return debt_total, debt_for\n\n\n@internal\n@view\ndef calculate_rate(_for: address, _price: uint256, ro: bool) -> (uint256, uint256):\n    sigma: int256 = self.sigma\n    target_debt_fraction: uint256 = self.target_debt_fraction\n\n    p: int256 = convert(_price, int256)\n    pk_debt: uint256 = 0\n    for pk: PegKeeper in self.peg_keepers:\n        if pk.address == empty(address):\n            break\n        pk_debt += staticcall pk.debt()\n\n    total_debt: uint256 = 0\n    debt_for: uint256 = 0\n    total_debt, debt_for = self.read_debt(_for, ro)\n\n    power: int256 = (10**18 - p) * 10**18 // sigma  # high price -> negative pow -> low rate\n    ratio: uint256 = 0\n    if pk_debt > 0:\n        if total_debt == 0:\n            return 0, 0\n        else:\n            ratio = pk_debt * 10**18 // total_debt\n            power -= convert(ema.read(DEBT_RATIO_EMA_ID) * 10**18 // target_debt_fraction, int256)\n\n    # Rate accounting for crvUSD price and PegKeeper debt\n    rate: uint256 = self.rate0 * min(self.exp(power), MAX_EXP) // 10**18 + self.extra_const\n\n    # Account for individual debt ceiling to dynamically tune rate depending on filling the market\n    ceiling: uint256 = staticcall CONTROLLER_FACTORY.debt_ceiling(_for)\n    if ceiling > 0:\n        f: uint256 = min(debt_for * 10**18 // ceiling, 10**18 - TARGET_REMAINDER // 1000)\n        rate = min(rate * ((10**18 - TARGET_REMAINDER) + TARGET_REMAINDER * 10**18 // (10**18 - f)) // 10**18, MAX_RATE)\n\n    # Rate multiplication at different ceilings (target = 0.1):\n    # debt = 0:\n    #   new_rate = rate * ((1.0 - target) + target) = rate\n    #\n    # debt = ceiling:\n    #   f = 1.0 - 0.1 / 1000 = 0.9999  # instead of infinity to avoid /0\n    #   new_rate = min(rate * ((1.0 - target) + target / (1.0 - 0.9999)), max_rate) = max_rate\n    #\n    # debt = 0.9 * ceiling, target = 0.1\n    #   f = 0.9\n    #   new_rate = rate * ((1.0 - 0.1) + 0.1 / (1.0 - 0.9)) = rate * (1.0 + 1.0 - 0.1) = 1.9 * rate\n\n    return rate, ratio\n\n\n@view\n@external\ndef rate(_for: address = msg.sender) -> uint256:\n    rate: uint256 = 0\n    _: uint256 = 0\n    rate, _ = self.calculate_rate(_for, staticcall PRICE_ORACLE.price(), True)\n    return rate\n\n\n@external\ndef rate_write(_for: address = msg.sender) -> uint256:\n    # Update controller list\n    n_controllers: uint256 = self.n_controllers\n    n_factory_controllers: uint256 = staticcall CONTROLLER_FACTORY.n_collaterals()\n    if n_factory_controllers > n_controllers:\n        self.n_controllers = n_factory_controllers\n        for i: uint256 in range(MAX_CONTROLLERS):\n            self.controllers[n_controllers] = staticcall CONTROLLER_FACTORY.controllers(n_controllers)\n            n_controllers += 1\n            if n_controllers >= n_factory_controllers:\n                break\n\n    # Update candles\n    total_debt: uint256 = 0\n    debt_for: uint256 = 0\n    total_debt, debt_for = self.get_total_debt(_for)\n    self.save_candle(empty(address), total_debt)\n    self.save_candle(_for, debt_for)\n\n    rate: uint256 = 0\n    ratio: uint256 = 0\n    rate, ratio = self.calculate_rate(_for, extcall PRICE_ORACLE.price_w(), False)\n    ema.update(DEBT_RATIO_EMA_ID, ratio)\n    return rate\n\n\n@external\ndef set_rate(rate: uint256):\n    assert msg.sender == self.admin  # dev: only admin\n    assert rate <= MAX_RATE  # dev: rate too high\n    self.rate0 = rate\n    log SetRate(rate=rate)\n\n\n@external\ndef set_sigma(sigma: int256):\n    assert msg.sender == self.admin  # dev: only admin\n    assert sigma >= MIN_SIGMA  # dev: sigma too low\n    assert sigma <= MAX_SIGMA  # dev: sigma too high\n\n    self.sigma = sigma\n    log SetSigma(sigma=sigma)\n\n\n@external\ndef set_target_debt_fraction(target_debt_fraction: uint256):\n    assert msg.sender == self.admin  # dev: only admin\n    assert target_debt_fraction <= MAX_TARGET_DEBT_FRACTION  # dev: target debt fraction too high\n    assert target_debt_fraction > 0  # dev: target debt fraction is zero\n\n    self.target_debt_fraction = target_debt_fraction\n    log SetTargetDebtFraction(target_debt_fraction=target_debt_fraction)\n\n\n@external\ndef set_extra_const(extra_const: uint256):\n    assert msg.sender == self.admin  # dev: only admin\n    assert extra_const <= MAX_EXTRA_CONST  # dev: extra const too high\n\n    self.extra_const = extra_const\n    log SetExtraConst(extra_const=extra_const)\n\n\n@external\ndef set_debt_ratio_ema_time(_debt_ratio_ema_time: uint256):\n    assert msg.sender == self.admin  # dev: only admin\n\n    ema.set_ema_time(DEBT_RATIO_EMA_ID, _debt_ratio_ema_time)\n    log SetDebtRatioEmaTime(debt_ratio_ema_time=_debt_ratio_ema_time)\n\n@external\n@view\ndef debt_ratio_ema_time() -> uint256:\n    return ema._emas[DEBT_RATIO_EMA_ID].ema_time\n","deployed_bytecode":"0x5f3560e01c60026019820660011b611a4001601e395f51565b63e9333fab811861007857602436103417611a3c576004358060a01c611a3c576040526001543318611a3c576040516001557f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a160405160605260206060a1005b63f623513881186109ef57602436103417611a3c576004356103e9811015611a3c576006015460405260206040f35b630eb57e3c81186101ce57602436103417611a3c576004358060a01c611a3c576040526001543318611a3c5760405115611a3c575f6103e8905b806060526060516103e9811015611a3c5760060154608052604051608051186101775760208061010052600d60a0527f416c72656164792061646465640000000000000000000000000000000000000060c05260a08161010001602d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060e0528060040160fcfd5b6080516101bf576040516060516103e9811015611a3c57600601556040517ff395c3706a8194522b942d1992143a7b60a92a83f99ec30e3833c7630e3c13315f60a0a26101ca565b6001018181186100e1575b5050005b630a19399a81186109ef5734611a3c576020611d1260403960206040f35b6355aab44a81186109ef57602436103417611a3c576004358060a01c611a3c576040526001543318611a3c576127106060525f6103e9905b806080526080516103e9811015611a3c576006015460a05260405160a05118610276576080516060526040517f52182c3057b74a074adcacf89ba9ff9860a1265c89cfecd998a111e06bc802675f60c0a25b60a0516102f65760805160605110156103015760805160018103818111611a3c57905060605110156102d25760805160018103818111611a3c5790506103e9811015611a3c57600601546060516103e9811015611a3c57600601555b5f60805160018103818111611a3c5790506103e9811015611a3c5760060155610301565b600101818118610224575b5050005b632c4e722e81186109ef5734611a3c573361056052610344565b630ba9d8ca81186109ef57602436103417611a3c576004358060a01c611a3c57610560525b6040366105803761056051610380526020611d125f395f5163a035b1fe6105c05260206105c060046105dc845afa61037e573d5f5f3e3d5ffd5b60203d10611a3c576105c09050516103a05260016103c0526103a16106006113f3565b6106006040816106405e5060406106406105805e6020610580f35b63e91f2f4c81186103d65734611a3c573361056052610417565b63afdf31cd81186109ef5734611a3c5760035460405260206040f35b63bdb09f2e811861063e57602436103417611a3c576004358060a01c611a3c57610560525b6103ef54610580526020611d325f395f516312397fa16105c05260206105c060046105dc845afa61044a573d5f5f3e3d5ffd5b60203d10611a3c576105c09050516105a052610580516105a0511115610523576105a0516103ef555f61c350905b806105c0526020611d325f395f5163e94b0dd26105e052610580516106005260206105e060246105fc845afa6104b0573d5f5f3e3d5ffd5b3d602081183d6020100218806105e00161060011611a3c576105e0518060a01c611a3c5761062052506106209050516105805161c350811015611a3c576103f001556105805160018101818110611a3c579050610580526105a05161058051101561052057600101818118610478575b50505b6040366105c0376105605160405261053c610600610abb565b6106006040816106405e5060406106406105c05e5f6040526105c0516060526105636117cc565b610560516040526105e0516060526105796117cc565b6040366106003761056051610380526020611d125f395f5163ceb7f759610640526020610640600461065c5f855af16105b4573d5f5f3e3d5ffd5b60203d10611a3c576106409050516103a0525f6103c0526105d66106806113f3565b6106806040816106c05e5060406106c06106005e6003610640527f706b720000000000000000000000000000000000000000000000000000000000610660526106406023816102405e5061062051610280526106336106806118ce565b610680506020610600f35b635e7d44f881186109ef57602436103417611a3c576001543318611a3c57640a3c2abcef60043511611a3c576004356005557f1fad4e90c91f695c13fb8fb3a632a565c3aa742ade9d609cdcb639644e90a27460043560405260206040a1005b63d4387a9981186106fe57602436103417611a3c576001543318611a3c57640a3c2abcef60043511611a3c576004356002557f2640b4015d3473fd09bf2b30939e17deb4068cdacf3892136e737e166ceb321060043560405260206040a1005b63592263e281186109ef5734611a3c5760055460405260206040f35b63bc8f1050811861078c57602436103417611a3c576001543318611a3c57655af3107a400060043512611a3c57670de0b6b3a764000060043513611a3c576004356003557fdd7b7d5ad5206db1e2995b71e974a52e324ffefe428b26c79f323b814de1d15560043560405260206040a1005b63f851a44081186109ef5734611a3c5760015460405260206040f35b63c18b939681186109ef57602436103417611a3c576001543318611a3c57670de0b6b3a764000060043511611a3c5760043515611a3c576004356004557f282d6b198c8375838e9528471dafbdbbee8d421fb7fa793395872d42da32fa2b60043560405260206040a1005b6326cfedb781186109ef57602436103417611a3c576001543318611a3c576003610420527f706b720000000000000000000000000000000000000000000000000000000000610440526104206023816103405e5060043561038052610876611970565b7f3d1c6eece46d835c9c1dfc71022e16ff4270f631ee54aeadef907bce23c6c020600435610420526020610420a1005b63eb1ca27981186109ef5734611a3c575f60036040527f706b72000000000000000000000000000000000000000000000000000000000060605260408051602082012090506020525f5260405f205460805260206080f35b6393c19e1881186109ef5734611a3c5760025460405260206040f35b63a155b53a81186109ef5734611a3c5760045460405260206040f35b63a38d1b2181186109ef5734611a3c576020611d3260403960206040f35b631d74182581186109ef5734611a3c576103ef5460405260206040f35b63e94b0dd281186109ef57602436103417611a3c5760043561c350811015611a3c576103f0015460405260206040f35b635db441ed81186109ef57602436103417611a3c576004358060a01c611a3c5760405261c7406040516020525f5260405f2080546060526001810154608052600281015460a0525060606060f35b5f5ffd5b5f60605261c7406040516020525f5260405f208054608052600181015460a052600281015460c0525060c05161a8c08104905061a8c081028161a8c0820418611a3c57905061a8c08101818110611a3c5790504210610a895760c05161a8c08104905061a8c081028161a8c0820418611a3c579050620151808101818110611a3c579050421015610ab35760a051606052610ab3565b60805115610aac5760805160a05180828118828410021890509050606052610ab3565b60a0516060525b606051815250565b6103ef546060526040366080375f61c350905b8060c05260605160c0511015610bb85760c05161c350811015611a3c576103f0015460e0526040366101003760e0515a6004610160527f31dc3ca800000000000000000000000000000000000000000000000000000000610180526101605060206101c0610160516101808585fa905090506101e0523d602081183d60201002186101a0526101a06040816102005e506101e0516101005260406102006101205e610140516101205160200360031b1c6101605260805161016051808201828110611a3c579050905060805260405160e05118610bad576101605160a0525b600101818118610ace575b5050608051815260a051602082015250565b5f604052610bd96102a06109f3565b6102a0516102805261024051604052610bf36102c06109f3565b6102c0516102a0526040366102c03761026051610c705761028051610c19576001610c1f565b6102a051155b15610cf65761024051604052610c36610300610abb565b6103006040816103405e5060406103406102c05e61028051610c5b576102c051610280525b6102a051610cf6576102e0516102a052610cf6565b61024051604052610c82610300610abb565b6103006040816103405e5060406103406102c05e6102805115610cbd57610280516102c0518082811882841002189050905061028052610cc6565b6102c051610280525b6102a05115610ced576102a0516102e051808281188284100218905090506102a052610cf6565b6102e0516102a0525b6102805181526102a051602082015250565b5f6020611a725f395f51600a8111611a3c578015610d5c57905b8060061b602001602481611a72016080395060405160602060805160a02018610d515760018352505050610d63565b600101818118610d22575b50505f8152505b565b7ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a462d760405113610d97575f815250610fca565b680755bf798b4a1bf1e46040511315610e1b5760208060c05260166060527f6d6174683a207761645f657870206f766572666c6f770000000000000000000060805260608160c001603682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060a0528060040160bcfd5b6503782dace9d9604051604e1b056040526b8000000000000000000000006bb17217f7d1cf79abc9e3b39860405160601b050160601d6060526bb17217f7d1cf79abc9e3b39860605102604051036040526d02d16720577bd19bf614176fe9ea6040516c10fe68e7fd37d0007b713f7650604051010260601d0160805279d835ebba824c98fb31b83b2ca45c0000000000000000000000006040516e0587f503bb6ea29d25fcb7401964506080516d04a4fd9f2a8b96949216d2255a6c60405160805101030260601d01020160a0526d0277594991cfc85f6e2461837cd96040516c240c330e9fb2d9cbaf0fd5aafc604051030260601d0160c0526d1a521255e34f6a5061b25ef1c9c460405160c0510260601d0360c0526db1bbb201f443cf962f1a1d3db4a560405160c0510260601d0160c0526e02c72388d9f74f51a9331fed693f1560405160c0510260601d0360c0526e05180bb14799ab47a8a8cb2a527d5760405160c0510260601d0160c05260c05160a0510560e05274029d9dc38563c32e5c2f6dc192ee70ef65f9978af360e0510260605160c3035f8112611a3c571c8060ff1c611a3c578152505b565b602461012060405e610fdf610160610d08565b6101605115611a3c575f61012051610140206020525f5260405f2080546101605260018101546101805260028101546101a05260038101546101c05250426101a051808203828111611a3c57905090506101e0526101e051611047576101805181525061113b565b6101e051670de0b6b3a7640000810281670de0b6b3a7640000820418611a3c579050610160518015611a3c57808204905090508060ff1c611a3c577f80000000000000000000000000000000000000000000000000000000000000008114611a3c575f036040526110b9610220610d65565b610220515f8112611a3c57610200526101805161020051808202811583838304141715611a3c57905090506101c0516102005180670de0b6b3a764000003670de0b6b3a76400008111611a3c579050808202811583838304141715611a3c5790509050808201828110611a3c5790509050670de0b6b3a7640000810490508152505b565b7ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a466806040511361116f575f8152506113f1565b680755bf798b4a1bf1e56040511261119357683635c9adc5dea000008152506113f1565b670de0b6b3a764000060405160601b056060526c010000000000000000000000006b8000000000000000000000006bb17217f7d1cf79abc9e3b39860605160601b0501056080526bb17217f7d1cf79abc9e3b39860805102606051036060526c10fe68e7fd37d0007b713f76506060510160a0526d02d16720577bd19bf614176fe9ea6c0100000000000000000000000060605160a05102050160a0526d04a4fd9f2a8b96949216d2255a6c60605160a051010360c0526e0587f503bb6ea29d25fcb7401964506c0100000000000000000000000060a05160c05102050160c05279d835ebba824c98fb31b83b2ca45c00000000000000000000000060605160c051020160c0526060516c240c330e9fb2d9cbaf0fd5aafc8103818113611a3c57905060e0526d0277594991cfc85f6e2461837cd96c0100000000000000000000000060605160e05102050160e0526d1a521255e34f6a5061b25ef1c9c46c0100000000000000000000000060605160e05102050360e0526db1bbb201f443cf962f1a1d3db4a56c0100000000000000000000000060605160e05102050160e0526e02c72388d9f74f51a9331fed693f156c0100000000000000000000000060605160e05102050360e0526e05180bb14799ab47a8a8cb2a527d576c0100000000000000000000000060605160e05102050160e05274029d9dc38563c32e5c2f6dc192ee70ef65f9978af360e05160c051055f8112611a3c570260c3608051037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8113156113e35781811b6113e9565b81815f031c5b905090508152505b565b6003546103e052600454610400526103a0518060ff1c611a3c57610420525f610440525f6103e9905b8060060154610460526104605115611483576104405161046051630dca59c1610480526020610480600461049c845afa611458573d5f5f3e3d5ffd5b60203d10611a3c57610480905051808201828110611a3c57905090506104405260010181811861141c575b50506040366104603761038051610240526103c051610260526114a76104a0610bca565b6104a06040816104e05e5060406104e06104605e6104205180670de0b6b3a764000003670de0b6b3a764000081135f831218611a3c579050670de0b6b3a7640000810281670de0b6b3a7640000820518611a3c5790506103e0518015611a3c57808205600160ff1b8314155f198314151715611a3c57905090506104a0525f6104c0526104405115611618576104605161154a575f81525f6020820152506117ca565b61044051670de0b6b3a7640000810281670de0b6b3a7640000820418611a3c579050610460518015611a3c57808204905090506104c0526104a05160036104e0527f706b720000000000000000000000000000000000000000000000000000000000610500526104e06023816101205e506115c6610520610fcc565b61052051670de0b6b3a7640000810281670de0b6b3a7640000820418611a3c579050610400518015611a3c57808204905090508060ff1c611a3c578082038281135f831218611a3c57905090506104a0525b6002546104a05160405261162d61050061113d565b61050051683635c9adc5dea00000818118683635c9adc5dea00000831002189050808202811583838304141715611a3c5790509050670de0b6b3a764000081049050600554808201828110611a3c57905090506104e0526020611d325f395f5163602b62d46105205261038051610540526020610520602461053c845afa6116b7573d5f5f3e3d5ffd5b60203d10611a3c576105209050516105005261050051156117b95761048051670de0b6b3a7640000810281670de0b6b3a7640000820418611a3c579050610500518015611a3c5780820490509050670de05bc096e9c000818118670de05bc096e9c000831002189050610520526104e0516105205180670de0b6b3a764000003670de0b6b3a76400008111611a3c5790508015611a3c57806e13426172c74d822b878fe80000000004905080670c7d713b49da000001670c7d713b49da00008110611a3c579050808202811583838304141715611a3c5790509050670de0b6b3a764000081049050640a3c2abcef818118640a3c2abcef8310021890506104e0525b6104e05181526104c0516020820152505b565b61c7406040516020525f5260405f208054608052600181015460a052600281015460c0525060c0516118015760605115611803565b5f5b6118cc5760c05161a8c08104905061a8c081028161a8c0820418611a3c57905061a8c08101818110611a3c5790504210156118535760a0516060518082811882841002189050905060a0526118a2565b60c05161a8c08104905061a8c081028161a8c0820418611a3c579050620151808101818110611a3c57905042106118955760605160805260605160a0526118a2565b60a05160805260605160a0525b4260c05261c7406040516020525f5260405f20608051815560a051600182015560c0516002820155505b565b60246102406101205e6118e26102c0610fcc565b6102c0516102a0525f61024051610260206020525f5260405f2080546102c05260018101546102e052600281015461030052600381015461032052506102a0516102e052426103005261028051610320525f61024051610260206020525f5260405f206102c05181556102e0516001820155610300516002820155610320516003820155506102a051815250565b602461034060405e6119836103a0610d08565b6103a05115611a3c5760246103406102405e5f61034051610360206020525f5260405f2060038101905054610280526119bd6103a06118ce565b6103a0506103805115611a3c575f61034051610360206020525f5260405f2080546103a05260018101546103c05260028101546103e05260038101546104005250610380516103a0525f61034051610360206020525f5260405f206103a05181556103c05160018201556103e051600282015561040051600382015550565b5f80fd09ef09ef03bc09ef0936091a00a7071a031f01ec03f208a609ef001809ef081309710305069e09ef09a1095408fe09ef07a800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003706b72000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018672b1b0c623a30089a280ed9256379fb0e4e62000000000000000000000000c9332fdcb1c491dcc683bae86fe3cb70360738bc","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"outputSelection":{"curve_stablecoin/mpolicies/AggMonetaryPolicy4.vy":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]},"search_paths":[".",".venv/lib/python3.10/site-packages"]},"optimization_runs":null,"sourcify_repo_url":null,"decoded_constructor_args":[["0x40907540d8a6C65c637785e8f8B742ae6b0b9968",{"name":"admin","type":"address"}],["0x18672b1b0c623a30089A280Ed9256379fb0E4E62",{"name":"price_oracle","type":"address"}],["0xC9332fdCB1C491Dcc683bAe86Fe3cb70360738BC",{"name":"controller_factory","type":"address"}],[["0x9201da0D97CaAAff53f01B2fB56767C7072dE340","0xFb726F57d251aB5C731E5C64eD4F5F94351eF9F3","0x3fA20eAa107DE08B38a8734063D605d5842fe09C","0x338Cb2D827112d989A861cDe87CD9FfD913A1f9D","0x0000000000000000000000000000000000000000"],{"name":"peg_keepers","type":"address[5]"}],["3662480974",{"name":"rate","type":"uint256"}],["7000000000000000",{"name":"sigma","type":"int256"}],["266700000000000000",{"name":"target_debt_fraction","type":"uint256"}],["0",{"name":"extra_const","type":"uint256"}],["777600",{"name":"_debt_ratio_ema_time","type":"uint256"}]],"compiler_version":"v0.4.3+commit.bff19ea2","is_verified_via_verifier_alliance":false,"verified_at":"2026-01-31T17:52:54.852675Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x611d32515034610379576020611e285f395f518060a01c61037957610900526020611e485f395f518060a01c61037957610920526020611e685f395f518060a01c61037957610940526020611e885f395f518060a01c61037957610960526020611ea85f395f518060a01c61037957610980526020611ec85f395f518060a01c610379576109a0526020611ee85f395f518060a01c610379576109c0526020611f085f395f518060a01c610379576109e0526109005160015561092051611d125261094051611d32525f6005905b80610a0052610a005160058110156103795760051b61096001511561011e57610a005160058110156103795760051b6109600151610a00516103e981101561037957600601556001018181186100cd575b5050655af3107a40006020611f485f395f511261037957670de0b6b3a76400006020611f485f395f5113610379576020611f685f395f511561037957670de0b6b3a76400006020611f685f395f511161037957640a3c2abcef6020611f285f395f511161037957640a3c2abcef6020611f885f395f5111610379576020611f285f395f516002556020611f485f395f516003556020611f685f395f516004556020611f885f395f516005556003610a00527f706b720000000000000000000000000000000000000000000000000000000000610a2052610a0060238160605e506020611f6860a0396020611fa860c039600160405261021b61022d565b611a7261037d61000039611d52610000f35b5f610560525f604051600a811161037957801561032157905b8060071b6060016024816108005e6040810151610840526060810151610860525061086051156103795760246108006108805e5f61056051600a81116103795780156102be57905b8060061b610580016024816108c05e50610880516108a0206108c0516108e020146103795760010181811861028e575b50505f610880516108a0206020525f5260405f20610860518155610840516001820155426002820155610840516003820155506105605160098111610379578060061b610580016024610880825e50600181016105605250600101818118610246575b5050610560515f81600a811161037957801561036f57905b8060061b6105800180518260061b602001611a720152602081015160208360061b60200101611a72015250600101818118610339575b505080611a725250565b5f80fd5f3560e01c60026019820660011b611a4001601e395f51565b63e9333fab811861007857602436103417611a3c576004358060a01c611a3c576040526001543318611a3c576040516001557f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a160405160605260206060a1005b63f623513881186109ef57602436103417611a3c576004356103e9811015611a3c576006015460405260206040f35b630eb57e3c81186101ce57602436103417611a3c576004358060a01c611a3c576040526001543318611a3c5760405115611a3c575f6103e8905b806060526060516103e9811015611a3c5760060154608052604051608051186101775760208061010052600d60a0527f416c72656164792061646465640000000000000000000000000000000000000060c05260a08161010001602d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060e0528060040160fcfd5b6080516101bf576040516060516103e9811015611a3c57600601556040517ff395c3706a8194522b942d1992143a7b60a92a83f99ec30e3833c7630e3c13315f60a0a26101ca565b6001018181186100e1575b5050005b630a19399a81186109ef5734611a3c576020611d1260403960206040f35b6355aab44a81186109ef57602436103417611a3c576004358060a01c611a3c576040526001543318611a3c576127106060525f6103e9905b806080526080516103e9811015611a3c576006015460a05260405160a05118610276576080516060526040517f52182c3057b74a074adcacf89ba9ff9860a1265c89cfecd998a111e06bc802675f60c0a25b60a0516102f65760805160605110156103015760805160018103818111611a3c57905060605110156102d25760805160018103818111611a3c5790506103e9811015611a3c57600601546060516103e9811015611a3c57600601555b5f60805160018103818111611a3c5790506103e9811015611a3c5760060155610301565b600101818118610224575b5050005b632c4e722e81186109ef5734611a3c573361056052610344565b630ba9d8ca81186109ef57602436103417611a3c576004358060a01c611a3c57610560525b6040366105803761056051610380526020611d125f395f5163a035b1fe6105c05260206105c060046105dc845afa61037e573d5f5f3e3d5ffd5b60203d10611a3c576105c09050516103a05260016103c0526103a16106006113f3565b6106006040816106405e5060406106406105805e6020610580f35b63e91f2f4c81186103d65734611a3c573361056052610417565b63afdf31cd81186109ef5734611a3c5760035460405260206040f35b63bdb09f2e811861063e57602436103417611a3c576004358060a01c611a3c57610560525b6103ef54610580526020611d325f395f516312397fa16105c05260206105c060046105dc845afa61044a573d5f5f3e3d5ffd5b60203d10611a3c576105c09050516105a052610580516105a0511115610523576105a0516103ef555f61c350905b806105c0526020611d325f395f5163e94b0dd26105e052610580516106005260206105e060246105fc845afa6104b0573d5f5f3e3d5ffd5b3d602081183d6020100218806105e00161060011611a3c576105e0518060a01c611a3c5761062052506106209050516105805161c350811015611a3c576103f001556105805160018101818110611a3c579050610580526105a05161058051101561052057600101818118610478575b50505b6040366105c0376105605160405261053c610600610abb565b6106006040816106405e5060406106406105c05e5f6040526105c0516060526105636117cc565b610560516040526105e0516060526105796117cc565b6040366106003761056051610380526020611d125f395f5163ceb7f759610640526020610640600461065c5f855af16105b4573d5f5f3e3d5ffd5b60203d10611a3c576106409050516103a0525f6103c0526105d66106806113f3565b6106806040816106c05e5060406106c06106005e6003610640527f706b720000000000000000000000000000000000000000000000000000000000610660526106406023816102405e5061062051610280526106336106806118ce565b610680506020610600f35b635e7d44f881186109ef57602436103417611a3c576001543318611a3c57640a3c2abcef60043511611a3c576004356005557f1fad4e90c91f695c13fb8fb3a632a565c3aa742ade9d609cdcb639644e90a27460043560405260206040a1005b63d4387a9981186106fe57602436103417611a3c576001543318611a3c57640a3c2abcef60043511611a3c576004356002557f2640b4015d3473fd09bf2b30939e17deb4068cdacf3892136e737e166ceb321060043560405260206040a1005b63592263e281186109ef5734611a3c5760055460405260206040f35b63bc8f1050811861078c57602436103417611a3c576001543318611a3c57655af3107a400060043512611a3c57670de0b6b3a764000060043513611a3c576004356003557fdd7b7d5ad5206db1e2995b71e974a52e324ffefe428b26c79f323b814de1d15560043560405260206040a1005b63f851a44081186109ef5734611a3c5760015460405260206040f35b63c18b939681186109ef57602436103417611a3c576001543318611a3c57670de0b6b3a764000060043511611a3c5760043515611a3c576004356004557f282d6b198c8375838e9528471dafbdbbee8d421fb7fa793395872d42da32fa2b60043560405260206040a1005b6326cfedb781186109ef57602436103417611a3c576001543318611a3c576003610420527f706b720000000000000000000000000000000000000000000000000000000000610440526104206023816103405e5060043561038052610876611970565b7f3d1c6eece46d835c9c1dfc71022e16ff4270f631ee54aeadef907bce23c6c020600435610420526020610420a1005b63eb1ca27981186109ef5734611a3c575f60036040527f706b72000000000000000000000000000000000000000000000000000000000060605260408051602082012090506020525f5260405f205460805260206080f35b6393c19e1881186109ef5734611a3c5760025460405260206040f35b63a155b53a81186109ef5734611a3c5760045460405260206040f35b63a38d1b2181186109ef5734611a3c576020611d3260403960206040f35b631d74182581186109ef5734611a3c576103ef5460405260206040f35b63e94b0dd281186109ef57602436103417611a3c5760043561c350811015611a3c576103f0015460405260206040f35b635db441ed81186109ef57602436103417611a3c576004358060a01c611a3c5760405261c7406040516020525f5260405f2080546060526001810154608052600281015460a0525060606060f35b5f5ffd5b5f60605261c7406040516020525f5260405f208054608052600181015460a052600281015460c0525060c05161a8c08104905061a8c081028161a8c0820418611a3c57905061a8c08101818110611a3c5790504210610a895760c05161a8c08104905061a8c081028161a8c0820418611a3c579050620151808101818110611a3c579050421015610ab35760a051606052610ab3565b60805115610aac5760805160a05180828118828410021890509050606052610ab3565b60a0516060525b606051815250565b6103ef546060526040366080375f61c350905b8060c05260605160c0511015610bb85760c05161c350811015611a3c576103f0015460e0526040366101003760e0515a6004610160527f31dc3ca800000000000000000000000000000000000000000000000000000000610180526101605060206101c0610160516101808585fa905090506101e0523d602081183d60201002186101a0526101a06040816102005e506101e0516101005260406102006101205e610140516101205160200360031b1c6101605260805161016051808201828110611a3c579050905060805260405160e05118610bad576101605160a0525b600101818118610ace575b5050608051815260a051602082015250565b5f604052610bd96102a06109f3565b6102a0516102805261024051604052610bf36102c06109f3565b6102c0516102a0526040366102c03761026051610c705761028051610c19576001610c1f565b6102a051155b15610cf65761024051604052610c36610300610abb565b6103006040816103405e5060406103406102c05e61028051610c5b576102c051610280525b6102a051610cf6576102e0516102a052610cf6565b61024051604052610c82610300610abb565b6103006040816103405e5060406103406102c05e6102805115610cbd57610280516102c0518082811882841002189050905061028052610cc6565b6102c051610280525b6102a05115610ced576102a0516102e051808281188284100218905090506102a052610cf6565b6102e0516102a0525b6102805181526102a051602082015250565b5f6020611a725f395f51600a8111611a3c578015610d5c57905b8060061b602001602481611a72016080395060405160602060805160a02018610d515760018352505050610d63565b600101818118610d22575b50505f8152505b565b7ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a462d760405113610d97575f815250610fca565b680755bf798b4a1bf1e46040511315610e1b5760208060c05260166060527f6d6174683a207761645f657870206f766572666c6f770000000000000000000060805260608160c001603682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060a0528060040160bcfd5b6503782dace9d9604051604e1b056040526b8000000000000000000000006bb17217f7d1cf79abc9e3b39860405160601b050160601d6060526bb17217f7d1cf79abc9e3b39860605102604051036040526d02d16720577bd19bf614176fe9ea6040516c10fe68e7fd37d0007b713f7650604051010260601d0160805279d835ebba824c98fb31b83b2ca45c0000000000000000000000006040516e0587f503bb6ea29d25fcb7401964506080516d04a4fd9f2a8b96949216d2255a6c60405160805101030260601d01020160a0526d0277594991cfc85f6e2461837cd96040516c240c330e9fb2d9cbaf0fd5aafc604051030260601d0160c0526d1a521255e34f6a5061b25ef1c9c460405160c0510260601d0360c0526db1bbb201f443cf962f1a1d3db4a560405160c0510260601d0160c0526e02c72388d9f74f51a9331fed693f1560405160c0510260601d0360c0526e05180bb14799ab47a8a8cb2a527d5760405160c0510260601d0160c05260c05160a0510560e05274029d9dc38563c32e5c2f6dc192ee70ef65f9978af360e0510260605160c3035f8112611a3c571c8060ff1c611a3c578152505b565b602461012060405e610fdf610160610d08565b6101605115611a3c575f61012051610140206020525f5260405f2080546101605260018101546101805260028101546101a05260038101546101c05250426101a051808203828111611a3c57905090506101e0526101e051611047576101805181525061113b565b6101e051670de0b6b3a7640000810281670de0b6b3a7640000820418611a3c579050610160518015611a3c57808204905090508060ff1c611a3c577f80000000000000000000000000000000000000000000000000000000000000008114611a3c575f036040526110b9610220610d65565b610220515f8112611a3c57610200526101805161020051808202811583838304141715611a3c57905090506101c0516102005180670de0b6b3a764000003670de0b6b3a76400008111611a3c579050808202811583838304141715611a3c5790509050808201828110611a3c5790509050670de0b6b3a7640000810490508152505b565b7ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a466806040511361116f575f8152506113f1565b680755bf798b4a1bf1e56040511261119357683635c9adc5dea000008152506113f1565b670de0b6b3a764000060405160601b056060526c010000000000000000000000006b8000000000000000000000006bb17217f7d1cf79abc9e3b39860605160601b0501056080526bb17217f7d1cf79abc9e3b39860805102606051036060526c10fe68e7fd37d0007b713f76506060510160a0526d02d16720577bd19bf614176fe9ea6c0100000000000000000000000060605160a05102050160a0526d04a4fd9f2a8b96949216d2255a6c60605160a051010360c0526e0587f503bb6ea29d25fcb7401964506c0100000000000000000000000060a05160c05102050160c05279d835ebba824c98fb31b83b2ca45c00000000000000000000000060605160c051020160c0526060516c240c330e9fb2d9cbaf0fd5aafc8103818113611a3c57905060e0526d0277594991cfc85f6e2461837cd96c0100000000000000000000000060605160e05102050160e0526d1a521255e34f6a5061b25ef1c9c46c0100000000000000000000000060605160e05102050360e0526db1bbb201f443cf962f1a1d3db4a56c0100000000000000000000000060605160e05102050160e0526e02c72388d9f74f51a9331fed693f156c0100000000000000000000000060605160e05102050360e0526e05180bb14799ab47a8a8cb2a527d576c0100000000000000000000000060605160e05102050160e05274029d9dc38563c32e5c2f6dc192ee70ef65f9978af360e05160c051055f8112611a3c570260c3608051037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8113156113e35781811b6113e9565b81815f031c5b905090508152505b565b6003546103e052600454610400526103a0518060ff1c611a3c57610420525f610440525f6103e9905b8060060154610460526104605115611483576104405161046051630dca59c1610480526020610480600461049c845afa611458573d5f5f3e3d5ffd5b60203d10611a3c57610480905051808201828110611a3c57905090506104405260010181811861141c575b50506040366104603761038051610240526103c051610260526114a76104a0610bca565b6104a06040816104e05e5060406104e06104605e6104205180670de0b6b3a764000003670de0b6b3a764000081135f831218611a3c579050670de0b6b3a7640000810281670de0b6b3a7640000820518611a3c5790506103e0518015611a3c57808205600160ff1b8314155f198314151715611a3c57905090506104a0525f6104c0526104405115611618576104605161154a575f81525f6020820152506117ca565b61044051670de0b6b3a7640000810281670de0b6b3a7640000820418611a3c579050610460518015611a3c57808204905090506104c0526104a05160036104e0527f706b720000000000000000000000000000000000000000000000000000000000610500526104e06023816101205e506115c6610520610fcc565b61052051670de0b6b3a7640000810281670de0b6b3a7640000820418611a3c579050610400518015611a3c57808204905090508060ff1c611a3c578082038281135f831218611a3c57905090506104a0525b6002546104a05160405261162d61050061113d565b61050051683635c9adc5dea00000818118683635c9adc5dea00000831002189050808202811583838304141715611a3c5790509050670de0b6b3a764000081049050600554808201828110611a3c57905090506104e0526020611d325f395f5163602b62d46105205261038051610540526020610520602461053c845afa6116b7573d5f5f3e3d5ffd5b60203d10611a3c576105209050516105005261050051156117b95761048051670de0b6b3a7640000810281670de0b6b3a7640000820418611a3c579050610500518015611a3c5780820490509050670de05bc096e9c000818118670de05bc096e9c000831002189050610520526104e0516105205180670de0b6b3a764000003670de0b6b3a76400008111611a3c5790508015611a3c57806e13426172c74d822b878fe80000000004905080670c7d713b49da000001670c7d713b49da00008110611a3c579050808202811583838304141715611a3c5790509050670de0b6b3a764000081049050640a3c2abcef818118640a3c2abcef8310021890506104e0525b6104e05181526104c0516020820152505b565b61c7406040516020525f5260405f208054608052600181015460a052600281015460c0525060c0516118015760605115611803565b5f5b6118cc5760c05161a8c08104905061a8c081028161a8c0820418611a3c57905061a8c08101818110611a3c5790504210156118535760a0516060518082811882841002189050905060a0526118a2565b60c05161a8c08104905061a8c081028161a8c0820418611a3c579050620151808101818110611a3c57905042106118955760605160805260605160a0526118a2565b60a05160805260605160a0525b4260c05261c7406040516020525f5260405f20608051815560a051600182015560c0516002820155505b565b60246102406101205e6118e26102c0610fcc565b6102c0516102a0525f61024051610260206020525f5260405f2080546102c05260018101546102e052600281015461030052600381015461032052506102a0516102e052426103005261028051610320525f61024051610260206020525f5260405f206102c05181556102e0516001820155610300516002820155610320516003820155506102a051815250565b602461034060405e6119836103a0610d08565b6103a05115611a3c5760246103406102405e5f61034051610360206020525f5260405f2060038101905054610280526119bd6103a06118ce565b6103a0506103805115611a3c575f61034051610360206020525f5260405f2080546103a05260018101546103c05260028101546103e05260038101546104005250610380516103a0525f61034051610360206020525f5260405f206103a05181556103c05160018201556103e051600282015561040051600382015550565b5f80fd09ef09ef03bc09ef0936091a00a7071a031f01ec03f208a609ef001809ef081309710305069e09ef09a1095408fe09ef07a8855820573c882aa44b8fb0f55a416b5596df4503b03354abb118c22861895aac66f61a191a728118321902e0a165767970657283000403003900000000000000000000000040907540d8a6c65c637785e8f8b742ae6b0b996800000000000000000000000018672b1b0c623a30089a280ed9256379fb0e4e62000000000000000000000000c9332fdcb1c491dcc683bae86fe3cb70360738bc0000000000000000000000009201da0d97caaaff53f01b2fb56767c7072de340000000000000000000000000fb726f57d251ab5c731e5c64ed4f5f94351ef9f30000000000000000000000003fa20eaa107de08b38a8734063d605d5842fe09c000000000000000000000000338cb2d827112d989a861cde87cd9ffd913a1f9d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000da4d064e0000000000000000000000000000000000000000000000000018de76816d800000000000000000000000000000000000000000000000000003b3823ca998c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bdd80","name":"AggMonetaryPolicy4","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"vyper","evm_version":null,"can_be_visualized_via_sol2uml":false,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":".venv/lib/python3.10/site-packages/curve_std/constants.vy","source_code":"# pragma version 0.4.3\n\nWAD: constant(uint256) = 10**18\nSWAD: constant(int256) = 10**18\n"},{"file_path":".venv/lib/python3.10/site-packages/curve_std/ema.vy","source_code":"# pragma version 0.4.3\n\"\"\"\n@notice Exponential Moving Average helper module.\n@author Curve Finance\n@dev - This module provides functionality to compute and persist\n     multiple EMAs identified by a string ID.\n     - The EMA is computed from the queued value from the\n     previous update, then queues the newly supplied value\n     for the next update to reduce manipulation risk.\n     - The module intentionally allows EMAs to be created at\n     construction time only.\n\"\"\"\n\nfrom curve_std import constants as c\nfrom snekmate.utils import math\n\n# @notice Exponential Moving Average instance\nstruct EMA:\n    ema_time: uint256\n    prev_value: uint256\n    prev_timestamp: uint256\n    queued_value: uint256\n\n\n# @notice Initial configuration for an EMA instance\nstruct EMAConfig:\n    ema_id: String[4]\n    initial_value: uint256\n    ema_time: uint256\n\n\n# @notice Wei Adjusted Decimal, represents 1.0 in 18 decimals fixed point.\nWAD: constant(uint256) = c.WAD\n# @notice Maximum number of different EMAs supported.\n# @dev Since Vyper doesn't support dynamic memory allocation\n# we keep this constant relatively small.\nMAX_EMAS: constant(uint256) = 10\n\n\n# @notice List of allowed EMAs ids.\n# @dev useful to expose in the contract importing\n# this module if it allows to pass arbitrary ids.\nALLOWED_EMAS: public(immutable(DynArray[String[4], MAX_EMAS]))\n\n# @dev Vyper doesn't support passing value by reference yet, so we use\n# a mapping and a 4 character string as a pointer to the corresponding\n# storage slot.\n# @dev This is not part of the public API and modifying it directly\n# may lead to unexpected behavior.\n_emas: HashMap[String[4], EMA]\n\n\n@deploy\ndef __init__(_ema_config: DynArray[EMAConfig, MAX_EMAS]):\n    \"\"\"\n    @notice Initialize the EMA instances based on the provided configuration.\n    @param _ema_config List of EMA configurations\n    \"\"\"\n    allow_list: DynArray[String[4], MAX_EMAS] = []\n    for config: EMAConfig in _ema_config:\n        # Setting an ema_time of 0 is not allowed, as it would break the math\n        assert config.ema_time > 0  # dev: invalid ema_time\n\n        id: String[4] = config.ema_id\n        for existing_id: String[4] in allow_list:\n            assert existing_id != id  # dev: duplicate ema id\n        self._emas[id] = EMA(\n            ema_time=config.ema_time,\n            prev_value=config.initial_value,\n            prev_timestamp=block.timestamp,\n            queued_value=config.initial_value,\n        )\n        allow_list.append(id)\n\n    ALLOWED_EMAS = allow_list\n\n\n@internal\n@view\ndef _is_allowed(_ema_id: String[4]) -> bool:\n    \"\"\"\n    @dev The `in` operator is not supported for DynArrays\n         in Vyper yet, so we implement this helper function.\n    @param _ema_id The identifier for the EMA\n    \"\"\"\n    for ema_id: String[4] in ALLOWED_EMAS:\n        if ema_id == _ema_id:\n            return True\n    return False\n\n\n@internal\ndef set_ema_time(_ema_id: String[4], _ema_time: uint256):\n    \"\"\"\n    @notice Update the ema_time for a given EMA id.\n    @dev Setting an ema_time of 0 is not allowed, as it would break the math.\n    @dev We first update the current EMA value to avoid discontinuities\n         in the smoothed value.\n    @param _ema_id The identifier for the EMA\n    @param _ema_time The new ema_time to set\n    \"\"\"\n    assert self._is_allowed(_ema_id)  # dev: id not allowed\n    self.update(_ema_id, self._emas[_ema_id].queued_value)\n    assert _ema_time > 0  # dev: invalid ema_time\n    ema: EMA = self._emas[_ema_id]\n    ema.ema_time = _ema_time\n    self._emas[_ema_id] = ema\n\n\n@internal\n@view\ndef read(_ema_id: String[4]) -> uint256:\n    \"\"\"\n    @notice Compute the EMA value for a given EMA id.\n    @dev The queued value from the previous update is used as input.\n    @dev block.timestamp is chain dependent and can be manipulated within\n         relatively small bounds. This can affect the EMA computation.\n    @param _ema_id The identifier for the EMA\n    @return The computed EMA value\n    \"\"\"\n    assert self._is_allowed(_ema_id)  # dev: id not allowed\n    ema: EMA = self._emas[_ema_id]\n\n    dt: uint256 = block.timestamp - ema.prev_timestamp\n\n    if dt == 0:\n        # The math below would return prev_value in this case anyway,\n        # but let's save some gas by skipping it\n        return ema.prev_value\n\n    mul: uint256 = convert(math._wad_exp(-convert(dt * WAD // ema.ema_time, int256)), uint256)\n    return (ema.prev_value * mul + ema.queued_value * (WAD - mul)) // WAD\n\n\n@internal\ndef update(_ema_id: String[4], _new_value: uint256) -> uint256:\n    \"\"\"\n    @notice Compute and persist the EMA value for a given EMA id.\n    @dev The queued value from the previous update is used as input, and\n         the new value is queued for the next update.\n    @dev The queueing mechanism helps to reduce manipulation risk, in a real\n         usage scenario a flash loan attacker would have to sustain their\n         beyond a single transaction to impact on the EMA, as repaying the\n         flash loan would queue a benign value for the next update.\n    @param _ema_id The identifier for the EMA\n    @param _new_value The new value to queue for the next update\n    @return The computed EMA value\n    \"\"\"\n    # (possibly) computing the smoothed value more than once\n    # in the same transaction to prioritize correctness.\n    # All other approaches considered so far would make the\n    # API of this library more error prone (e.g. direct access\n    # to storage variables can lead to inconsistent EMAs).\n    smoothed: uint256 = self.read(_ema_id)\n\n    ema: EMA = self._emas[_ema_id]\n    ema.prev_value = smoothed\n    ema.prev_timestamp = block.timestamp\n    ema.queued_value = _new_value\n    self._emas[_ema_id] = ema\n    return smoothed\n"},{"file_path":".venv/lib/python3.10/site-packages/snekmate/utils/math.vy","source_code":"# pragma version ~=0.4.3\n# pragma nonreentrancy off\n\"\"\"\n@title Standard Mathematical Utility Functions\n@custom:contract-name math\n@license GNU Affero General Public License v3.0 only\n@author pcaversaccio\n@custom:coauthor bout3fiddy\n@notice These functions implement standard mathematical utility\n        functions that are missing in the Vyper language. If a\n        function is inspired by an existing implementation, it\n        is properly referenced in the function docstring. The\n        following functions have been added for convenience:\n        - `_uint256_average` (`internal` `pure` function),\n        - `_int256_average` (`internal` `pure` function),\n        - `_ceil_div` (`internal` `pure` function),\n        - `_signum` (`internal` `pure` function),\n        - `_mul_div` (`internal` `pure` function),\n        - `_log2` (`internal` `pure` function),\n        - `_log10` (`internal` `pure` function),\n        - `_log256` (`internal` `pure` function),\n        - `_wad_ln` (`internal` `pure` function),\n        - `_wad_exp` (`internal` `pure` function),\n        - `_cbrt` (`internal` `pure` function),\n        - `_wad_cbrt` (`internal` `pure` function).\n\"\"\"\n\n\n@deploy\n@payable\ndef __init__():\n    \"\"\"\n    @dev To omit the opcodes for checking the `msg.value`\n         in the creation-time EVM bytecode, the constructor\n         is declared as `payable`.\n    \"\"\"\n    pass\n\n\n@internal\n@pure\ndef _uint256_average(x: uint256, y: uint256) -> uint256:\n    \"\"\"\n    @dev Returns the average of two 32-byte unsigned integers.\n    @notice Note that the result is rounded towards zero. For\n            more details on finding the average of two unsigned\n            integers without an overflow, please refer to:\n            https://devblogs.microsoft.com/oldnewthing/20220207-00/?p=106223.\n    @param x The first 32-byte unsigned integer of the data set.\n    @param y The second 32-byte unsigned integer of the data set.\n    @return uint256 The 32-byte average (rounded towards zero) of\n            `x` and `y`.\n    \"\"\"\n    return unsafe_add(x & y, (x ^ y) >> 1)\n\n\n@internal\n@pure\ndef _int256_average(x: int256, y: int256) -> int256:\n    \"\"\"\n    @dev Returns the average of two 32-byte signed integers.\n    @notice Note that the result is rounded towards infinity.\n            For more details on finding the average of two signed\n            integers without an overflow, please refer to:\n            https://patents.google.com/patent/US6007232A/en.\n    @param x The first 32-byte signed integer of the data set.\n    @param y The second 32-byte signed integer of the data set.\n    @return int256 The 32-byte average (rounded towards infinity)\n            of `x` and `y`.\n    \"\"\"\n    return unsafe_add(unsafe_add(x >> 1, y >> 1), x & y & 1)\n\n\n@internal\n@pure\ndef _ceil_div(x: uint256, y: uint256) -> uint256:\n    \"\"\"\n    @dev Calculates \"ceil(x / y)\" for any strictly positive `y`.\n    @notice The implementation is inspired by OpenZeppelin's\n            implementation here:\n            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.\n    @param x The 32-byte numerator.\n    @param y The 32-byte denominator.\n    @return uint256 The 32-byte rounded up result of \"x/y\".\n    \"\"\"\n    assert y != empty(uint256), \"math: ceil_div division by zero\"\n    # Due to a known compiler bug (https://github.com/vyperlang/vyper/issues/3480),\n    # we use `0` instead of `empty(uint256)` as return value.\n    return 0 if (x == empty(uint256)) else unsafe_add(unsafe_div(x - 1, y), 1)\n\n\n@internal\n@pure\ndef _signum(x: int256) -> int256:\n    \"\"\"\n    @dev Returns the indication of the sign of a 32-byte signed integer.\n    @notice The function returns `-1` if `x < 0`, `0` if `x == 0`, and `1`\n            if `x > 0`. For more details on finding the sign of a signed\n            integer, please refer to:\n            https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign.\n    @param x The 32-byte signed integer variable.\n    @return int256 The 32-byte sign indication (`1`, `0`, or `-1`) of `x`.\n    \"\"\"\n    return unsafe_sub(convert((x > empty(int256)), int256), convert((x < empty(int256)), int256))\n\n\n@internal\n@pure\ndef _mul_div(x: uint256, y: uint256, denominator: uint256, roundup: bool) -> uint256:\n    \"\"\"\n    @dev Calculates \"(x * y) / denominator\" in 512-bit precision,\n         following the selected rounding direction.\n    @notice The implementation is inspired by Remco Bloemen's\n            implementation under the MIT license here:\n            https://xn--2-umb.com/21/muldiv.\n            Furthermore, the rounding direction design pattern is\n            inspired by OpenZeppelin's implementation here:\n            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.\n    @param x The 32-byte multiplicand.\n    @param y The 32-byte multiplier.\n    @param denominator The 32-byte divisor.\n    @param roundup The Boolean variable that specifies whether\n           to round up or not. The default `False` is round down.\n    @return uint256 The 32-byte calculation result.\n    \"\"\"\n    # Handle division by zero.\n    assert denominator != empty(uint256), \"math: mul_div division by zero\"\n\n    # 512-bit multiplication \"[prod1 prod0] = x * y\".\n    # Compute the product \"mod 2**256\" and \"mod 2**256 - 1\".\n    # Then use the Chinese Remainder theorem to reconstruct\n    # the 512-bit result. The result is stored in two 256-bit\n    # variables, where: \"product = prod1 * 2**256 + prod0\".\n    mm: uint256 = uint256_mulmod(x, y, max_value(uint256))\n    # The least significant 256 bits of the product.\n    prod0: uint256 = unsafe_mul(x, y)\n    # The most significant 256 bits of the product.\n    prod1: uint256 = empty(uint256)\n\n    if mm < prod0:\n        prod1 = unsafe_sub(unsafe_sub(mm, prod0), 1)\n    else:\n        prod1 = unsafe_sub(mm, prod0)\n\n    # Handling of non-overflow cases, 256 by 256 division.\n    if prod1 == empty(uint256):\n        if roundup and uint256_mulmod(x, y, denominator) != empty(uint256):\n            # Calculate \"ceil((x * y) / denominator)\". The following\n            # line cannot overflow because we have the previous check\n            # \"(x * y) % denominator != 0\", which accordingly rules out\n            # the possibility of \"x * y = 2**256 - 1\" and `denominator == 1`.\n            return unsafe_add(unsafe_div(prod0, denominator), 1)\n\n        return unsafe_div(prod0, denominator)\n\n    # Ensure that the result is less than \"2**256\". Also,\n    # prevents that `denominator == 0`.\n    assert denominator > prod1, \"math: mul_div overflow\"\n\n    #######################\n    # 512 by 256 Division #\n    #######################\n\n    # Make division exact by subtracting the remainder\n    # from \"[prod1 prod0]\". First, compute remainder using\n    # the `uint256_mulmod` operation.\n    remainder: uint256 = uint256_mulmod(x, y, denominator)\n\n    # Second, subtract the 256-bit number from the 512-bit\n    # number.\n    if remainder > prod0:\n        prod1 = unsafe_sub(prod1, 1)\n    prod0 = unsafe_sub(prod0, remainder)\n\n    # Factor powers of two out of the denominator and calculate\n    # the largest power of two divisor of denominator. Always `>= 1`,\n    # unless the denominator is zero (which is prevented above),\n    # in which case `twos` is zero. For more details, please refer to:\n    # https://cs.stackexchange.com/q/138556.\n    twos: uint256 = unsafe_sub(empty(uint256), denominator) & denominator\n    # Divide denominator by `twos`.\n    denominator_div: uint256 = unsafe_div(denominator, twos)\n    # Divide \"[prod1 prod0]\" by `twos`.\n    prod0 = unsafe_div(prod0, twos)\n    # Flip `twos` such that it is \"2**256 / twos\". If `twos` is zero,\n    # it becomes one.\n    twos = unsafe_add(unsafe_div(unsafe_sub(empty(uint256), twos), twos), 1)\n\n    # Shift bits from `prod1` to `prod0`.\n    prod0 |= unsafe_mul(prod1, twos)\n\n    # Invert the denominator \"mod 2**256\". Since the denominator is\n    # now an odd number, it has an inverse modulo \"2**256\", so we have:\n    # \"denominator * inverse = 1 mod 2**256\". Calculate the inverse by\n    # starting with a seed that is correct for four bits. That is,\n    # \"denominator * inverse = 1 mod 2**4\".\n    inverse: uint256 = unsafe_mul(3, denominator_div) ^ 2\n\n    # Use Newton-Raphson iteration to improve accuracy. Thanks to Hensel's\n    # lifting lemma, this also works in modular arithmetic by doubling the\n    # correct bits in each step.\n    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse \"mod 2**8\".\n    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse \"mod 2**16\".\n    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse \"mod 2**32\".\n    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse \"mod 2**64\".\n    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse \"mod 2**128\".\n    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse \"mod 2**256\".\n\n    # Since the division is now exact, we can divide by multiplying\n    # with the modular inverse of the denominator. This returns the\n    # correct result modulo \"2**256\". Since the preconditions guarantee\n    # that the result is less than \"2**256\", this is the final result.\n    # We do not need to calculate the high bits of the result and\n    # `prod1` is no longer necessary.\n    result: uint256 = unsafe_mul(prod0, inverse)\n\n    if roundup and uint256_mulmod(x, y, denominator) != empty(uint256):\n        # Calculate \"ceil((x * y) / denominator)\". The following\n        # line uses intentionally checked arithmetic to prevent\n        # a theoretically possible overflow.\n        result += 1\n\n    return result\n\n\n@internal\n@pure\ndef _log2(x: uint256, roundup: bool) -> uint256:\n    \"\"\"\n    @dev Returns the log in base 2 of `x`, following the selected\n         rounding direction.\n    @notice Note that it returns `0` if given `0`. The implementation\n            is inspired by OpenZeppelin's implementation here:\n            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.\n    @param x The 32-byte variable.\n    @param roundup The Boolean variable that specifies whether\n           to round up or not. The default `False` is round down.\n    @return uint256 The 32-byte calculation result.\n    \"\"\"\n    # For the special case `x == 0`, we already return `0` here in order\n    # not to iterate through the remaining code.\n    if x == empty(uint256):\n        return empty(uint256)\n\n    value: uint256 = x\n    result: uint256 = empty(uint256)\n\n    # The following lines cannot overflow because we have the well-known\n    # decay behaviour of `log2(max_value(uint256)) < max_value(uint256)`.\n    if x >> 128 != empty(uint256):\n        x >>= 128\n        result = 128\n    if x >> 64 != empty(uint256):\n        x >>= 64\n        result = unsafe_add(result, 64)\n    if x >> 32 != empty(uint256):\n        x >>= 32\n        result = unsafe_add(result, 32)\n    if x >> 16 != empty(uint256):\n        x >>= 16\n        result = unsafe_add(result, 16)\n    if x >> 8 != empty(uint256):\n        x >>= 8\n        result = unsafe_add(result, 8)\n    if x >> 4 != empty(uint256):\n        x >>= 4\n        result = unsafe_add(result, 4)\n    if x >> 2 != empty(uint256):\n        x >>= 2\n        result = unsafe_add(result, 2)\n    if x >> 1 != empty(uint256):\n        result = unsafe_add(result, 1)\n\n    if roundup and (1 << result) < value:\n        result = unsafe_add(result, 1)\n\n    return result\n\n\n@internal\n@pure\ndef _log10(x: uint256, roundup: bool) -> uint256:\n    \"\"\"\n    @dev Returns the log in base 10 of `x`, following the selected\n         rounding direction.\n    @notice Note that it returns `0` if given `0`. The implementation\n            is inspired by OpenZeppelin's implementation here:\n            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.\n    @param x The 32-byte variable.\n    @param roundup The Boolean variable that specifies whether\n           to round up or not. The default `False` is round down.\n    @return uint256 The 32-byte calculation result.\n    \"\"\"\n    # For the special case `x == 0`, we already return `0` here in order\n    # not to iterate through the remaining code.\n    if x == empty(uint256):\n        return empty(uint256)\n\n    value: uint256 = x\n    result: uint256 = empty(uint256)\n\n    # The following lines cannot overflow because we have the well-known\n    # decay behaviour of `log10(max_value(uint256)) < max_value(uint256)`.\n    if x >= 10 ** 64:\n        x = unsafe_div(x, 10 ** 64)\n        result = 64\n    if x >= 10 ** 32:\n        x = unsafe_div(x, 10 ** 32)\n        result = unsafe_add(result, 32)\n    if x >= 10 ** 16:\n        x = unsafe_div(x, 10 ** 16)\n        result = unsafe_add(result, 16)\n    if x >= 10 ** 8:\n        x = unsafe_div(x, 10 ** 8)\n        result = unsafe_add(result, 8)\n    if x >= 10 ** 4:\n        x = unsafe_div(x, 10 ** 4)\n        result = unsafe_add(result, 4)\n    if x >= 10 ** 2:\n        x = unsafe_div(x, 10 ** 2)\n        result = unsafe_add(result, 2)\n    if x >= 10:\n        result = unsafe_add(result, 1)\n\n    if roundup and (10 ** result) < value:\n        result = unsafe_add(result, 1)\n\n    return result\n\n\n@internal\n@pure\ndef _log256(x: uint256, roundup: bool) -> uint256:\n    \"\"\"\n    @dev Returns the log in base 256 of `x`, following the selected\n         rounding direction.\n    @notice Note that it returns `0` if given `0`. Also, adding one to the\n            rounded down result gives the number of pairs of hex symbols\n            needed to represent `x` as a hex string. The implementation is\n            inspired by OpenZeppelin's implementation here:\n            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.\n    @param x The 32-byte variable.\n    @param roundup The Boolean variable that specifies whether\n           to round up or not. The default `False` is round down.\n    @return uint256 The 32-byte calculation result.\n    \"\"\"\n    # For the special case `x == 0`, we already return `0` here in order\n    # not to iterate through the remaining code.\n    if x == empty(uint256):\n        return empty(uint256)\n\n    value: uint256 = x\n    result: uint256 = empty(uint256)\n\n    # The following lines cannot overflow because we have the well-known\n    # decay behaviour of `log256(max_value(uint256)) < max_value(uint256)`.\n    if x >> 128 != empty(uint256):\n        x >>= 128\n        result = 16\n    if x >> 64 != empty(uint256):\n        x >>= 64\n        result = unsafe_add(result, 8)\n    if x >> 32 != empty(uint256):\n        x >>= 32\n        result = unsafe_add(result, 4)\n    if x >> 16 != empty(uint256):\n        x >>= 16\n        result = unsafe_add(result, 2)\n    if x >> 8 != empty(uint256):\n        result = unsafe_add(result, 1)\n\n    if roundup and (1 << (result << 3)) < value:\n        result = unsafe_add(result, 1)\n\n    return result\n\n\n@internal\n@pure\ndef _wad_ln(x: int256) -> int256:\n    \"\"\"\n    @dev Calculates the natural logarithm of a signed integer with a\n         precision of 1e18.\n    @notice Note that it returns `0` if given `0`. Furthermore, this function\n            consumes about 1,400 to 1,650 gas units depending on the value\n            of `x`. The implementation is inspired by Remco Bloemen's\n            implementation under the MIT license here:\n            https://xn--2-umb.com/22/exp-ln.\n    @param x The 32-byte variable.\n    @return int256 The 32-byte calculation result.\n    \"\"\"\n    assert x >= empty(int256), \"math: wad_ln undefined\"\n\n    # For the special case `x == 0`, we already return `0` here in order\n    # not to iterate through the remaining code.\n    if x == empty(int256):\n        return empty(int256)\n\n    # We want to convert `x` from \"10**18\" fixed point to \"2**96\"\n    # fixed point. We do this by multiplying by \"2**96 / 10**18\".\n    # But since \"ln(x * C) = ln(x) + ln(C)\" holds, we can just do\n    # nothing here and add \"ln(2**96 / 10**18)\" at the end.\n\n    # Reduce the range of `x` to \"(1, 2) * 2**96\".\n    # Also remember that \"ln(2**k * x) = k * ln(2) + ln(x)\" holds.\n    k: int256 = unsafe_sub(convert(self._log2(convert(x, uint256), False), int256), 96)\n    # Note that to circumvent Vyper's safecast feature for the potentially\n    # negative expression `x <<= uint256(159 - k)`, we first convert the\n    # expression `x <<= uint256(159 - k)` to `bytes32` and subsequently\n    # to `uint256`. Remember that the EVM default behaviour is to use two's\n    # complement representation to handle signed integers.\n    x = convert(convert(convert(x << convert(unsafe_sub(159, k), uint256), bytes32), uint256) >> 159, int256)\n\n    # Evaluate using a \"(8, 8)\"-term rational approximation. Since `p` is monic,\n    # we will multiply by a scaling factor later.\n    p: int256 = unsafe_add(\n        unsafe_mul(unsafe_add(x, 3_273_285_459_638_523_848_632_254_066_296), x) >> 96,\n        24_828_157_081_833_163_892_658_089_445_524,\n    )\n    p = unsafe_add(unsafe_mul(p, x) >> 96, 43_456_485_725_739_037_958_740_375_743_393)\n    p = unsafe_sub(unsafe_mul(p, x) >> 96, 11_111_509_109_440_967_052_023_855_526_967)\n    p = unsafe_sub(unsafe_mul(p, x) >> 96, 45_023_709_667_254_063_763_336_534_515_857)\n    p = unsafe_sub(unsafe_mul(p, x) >> 96, 14_706_773_417_378_608_786_704_636_184_526)\n    p = unsafe_sub(unsafe_mul(p, x), 795_164_235_651_350_426_258_249_787_498 << 96)\n\n    # We leave `p` in the \"2**192\" base so that we do not have to scale it up\n    # again for the division. Note that `q` is monic by convention.\n    q: int256 = unsafe_add(\n        unsafe_mul(unsafe_add(x, 5_573_035_233_440_673_466_300_451_813_936), x) >> 96,\n        71_694_874_799_317_883_764_090_561_454_958,\n    )\n    q = unsafe_add(unsafe_mul(q, x) >> 96, 283_447_036_172_924_575_727_196_451_306_956)\n    q = unsafe_add(unsafe_mul(q, x) >> 96, 401_686_690_394_027_663_651_624_208_769_553)\n    q = unsafe_add(unsafe_mul(q, x) >> 96, 204_048_457_590_392_012_362_485_061_816_622)\n    q = unsafe_add(unsafe_mul(q, x) >> 96, 31_853_899_698_501_571_402_653_359_427_138)\n    q = unsafe_add(unsafe_mul(q, x) >> 96, 909_429_971_244_387_300_277_376_558_375)\n\n    # It is known that the polynomial `q` has no zeros in the domain.\n    # No scaling is required, as `p` is already \"2**96\" too large. Also,\n    # `r` is in the range \"(0, 0.125) * 2**96\" after the division.\n    r: int256 = unsafe_div(p, q)\n\n    # To finalise the calculation, we have to proceed with the following steps:\n    #   - multiply by the scaling factor \"s = 5.549...\",\n    #   - add \"ln(2**96 / 10**18)\",\n    #   - add \"k * ln(2)\", and\n    #   - multiply by \"10**18 / 2**96 = 5**18 >> 78\".\n    # In order to perform the most gas-efficient calculation, we carry out all\n    # these steps in one expression.\n    return (\n        unsafe_add(\n            unsafe_add(\n                unsafe_mul(r, 1_677_202_110_996_718_588_342_820_967_067_443_963_516_166),\n                unsafe_mul(\n                    k, 16_597_577_552_685_614_221_487_285_958_193_947_469_193_820_559_219_878_177_908_093_499_208_371\n                ),\n            ),\n            600_920_179_829_731_861_736_702_779_321_621_459_595_472_258_049_074_101_567_377_883_020_018_308,\n        )\n        >> 174\n    )\n\n\n@internal\n@pure\ndef _wad_exp(x: int256) -> int256:\n    \"\"\"\n    @dev Calculates the natural exponential function of a signed integer with\n         a precision of 1e18.\n    @notice Note that this function consumes about 810 gas units. The implementation\n            is inspired by Remco Bloemen's implementation under the MIT license here:\n            https://xn--2-umb.com/22/exp-ln.\n    @param x The 32-byte variable.\n    @return int256 The 32-byte calculation result.\n    \"\"\"\n    # If the result is `< 1`, we return zero. This happens when we have the following:\n    # \"x <= (log(1e-18) * 1e18) ~ -4.15e19\".\n    if x <= -41_446_531_673_892_822_313:\n        return empty(int256)\n\n    # When the result is \"> (2**255 - 1) / 1e18\" we cannot represent it as a signed integer.\n    # This happens when \"x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135\".\n    assert x < 135_305_999_368_893_231_589, \"math: wad_exp overflow\"\n\n    # `x` is now in the range \"(-42, 136) * 1e18\". Convert to \"(-42, 136) * 2**96\" for higher\n    # intermediate precision and a binary base. This base conversion is a multiplication with\n    # \"1e18 / 2**96 = 5**18 / 2**78\".\n    x = unsafe_div(x << 78, 5 ** 18)\n\n    # Reduce the range of `x` to \"(-½ ln 2, ½ ln 2) * 2**96\" by factoring out powers of two\n    # so that \"exp(x) = exp(x') * 2**k\", where `k` is a signer integer. Solving this gives\n    # \"k = round(x / log(2))\" and \"x' = x - k * log(2)\". Thus, `k` is in the range \"[-61, 195]\".\n    k: int256 = unsafe_add(unsafe_div(x << 96, 54_916_777_467_707_473_351_141_471_128), 2 ** 95) >> 96\n    x = unsafe_sub(x, unsafe_mul(k, 54_916_777_467_707_473_351_141_471_128))\n\n    # Evaluate using a \"(6, 7)\"-term rational approximation. Since `p` is monic,\n    # we will multiply by a scaling factor later.\n    y: int256 = unsafe_add(\n        unsafe_mul(unsafe_add(x, 1_346_386_616_545_796_478_920_950_773_328), x) >> 96,\n        57_155_421_227_552_351_082_224_309_758_442,\n    )\n    p: int256 = unsafe_add(\n        unsafe_mul(\n            unsafe_add(\n                unsafe_mul(unsafe_sub(unsafe_add(y, x), 94_201_549_194_550_492_254_356_042_504_812), y) >> 96,\n                28_719_021_644_029_726_153_956_944_680_412_240,\n            ),\n            x,\n        ),\n        4_385_272_521_454_847_904_659_076_985_693_276 << 96,\n    )\n\n    # We leave `p` in the \"2**192\" base so that we do not have to scale it up\n    # again for the division.\n    q: int256 = unsafe_add(\n        unsafe_mul(unsafe_sub(x, 2_855_989_394_907_223_263_936_484_059_900), x) >> 96,\n        50_020_603_652_535_783_019_961_831_881_945,\n    )\n    q = unsafe_sub(unsafe_mul(q, x) >> 96, 533_845_033_583_426_703_283_633_433_725_380)\n    q = unsafe_add(unsafe_mul(q, x) >> 96, 3_604_857_256_930_695_427_073_651_918_091_429)\n    q = unsafe_sub(unsafe_mul(q, x) >> 96, 14_423_608_567_350_463_180_887_372_962_807_573)\n    q = unsafe_add(unsafe_mul(q, x) >> 96, 26_449_188_498_355_588_339_934_803_723_976_023)\n\n    # The polynomial `q` has no zeros in the range because all its roots are complex.\n    # No scaling is required, as `p` is already \"2**96\" too large. Also,\n    # `r` is in the range \"(0.09, 0.25) * 2**96\" after the division.\n    r: int256 = unsafe_div(p, q)\n\n    # To finalise the calculation, we have to multiply `r` by:\n    #   - the scale factor \"s = ~6.031367120\",\n    #   - the factor \"2**k\" from the range reduction, and\n    #   - the factor \"1e18 / 2**96\" for the base conversion.\n    # We do this all at once, with an intermediate result in \"2**213\" base,\n    # so that the final right shift always gives a positive value.\n\n    # Note that to circumvent Vyper's safecast feature for the potentially\n    # negative parameter value `r`, we first convert `r` to `bytes32` and\n    # subsequently to `uint256`. Remember that the EVM default behaviour is\n    # to use two's complement representation to handle signed integers.\n    return convert(\n        unsafe_mul(\n            convert(convert(r, bytes32), uint256), 3_822_833_074_963_236_453_042_738_258_902_158_003_155_416_615_667\n        )\n        >> convert(unsafe_sub(195, k), uint256),\n        int256,\n    )\n\n\n@internal\n@pure\ndef _cbrt(x: uint256, roundup: bool) -> uint256:\n    \"\"\"\n    @dev Calculates the cube root of an unsigned integer.\n    @notice Note that this function consumes about 1,600 to 1,800 gas units\n            depending on the value of `x` and `roundup`. The implementation is\n            inspired by Curve Finance's implementation under the MIT license here:\n            https://github.com/curvefi/tricrypto-ng/blob/main/contracts/main/CurveCryptoMathOptimized3.vy.\n    @param x The 32-byte variable from which the cube root is calculated.\n    @param roundup The Boolean variable that specifies whether\n           to round up or not. The default `False` is round down.\n    @return The 32-byte cube root of `x`.\n    \"\"\"\n    # For the special case `x == 0`, we already return `0` here in order\n    # not to iterate through the remaining code.\n    if x == empty(uint256):\n        return empty(uint256)\n\n    y: uint256 = unsafe_div(self._wad_cbrt(x), 10 ** 12)\n\n    if roundup and unsafe_mul(unsafe_mul(y, y), y) != x:\n        y = unsafe_add(y, 1)\n\n    return y\n\n\n@internal\n@pure\ndef _wad_cbrt(x: uint256) -> uint256:\n    \"\"\"\n    @dev Calculates the cube root of an unsigned integer with a precision\n         of 1e18.\n    @notice Note that this function consumes about 1,500 to 1,700 gas units\n            depending on the value of `x`. The implementation is inspired\n            by Curve Finance's implementation under the MIT license here:\n            https://github.com/curvefi/tricrypto-ng/blob/main/contracts/main/CurveCryptoMathOptimized3.vy.\n    @param x The 32-byte variable from which the cube root is calculated.\n    @return The 32-byte cubic root of `x` with a precision of 1e18.\n    \"\"\"\n    # For the special case `x == 0`, we already return `0` here in order\n    # not to iterate through the remaining code.\n    if x == empty(uint256):\n        return empty(uint256)\n\n    # Since this cube root is for numbers with base 1e18, we have to scale\n    # the input by 1e36 to increase the precision. This leads to an overflow\n    # for very large numbers. So we conditionally sacrifice precision.\n    value: uint256 = empty(uint256)\n    if x >= unsafe_mul(unsafe_div(max_value(uint256), 10 ** 36), 10 ** 18):\n        value = x\n    elif x >= unsafe_div(max_value(uint256), 10 ** 36):\n        value = unsafe_mul(x, 10 ** 18)\n    else:\n        value = unsafe_mul(x, 10 ** 36)\n\n    # Compute the binary logarithm of `value`.\n    log2x: uint256 = self._log2(value, False)\n\n    # If we divide log2x by 3, the remainder is \"log2x % 3\". So if we simply\n    # multiply \"2**(log2x/3)\" and discard the remainder to calculate our guess,\n    # the Newton-Raphson method takes more iterations to converge to a solution\n    # because it lacks this precision. A few more calculations now in order to\n    # do fewer calculations later:\n    #   - \"pow = log2(x) // 3\" (the operator `//` means integer division),\n    #   - \"remainder = log2(x) % 3\",\n    #   - \"initial_guess = 2**pow * cbrt(2)**remainder\".\n    # Now substituting \"2 = 1.26 ≈ 1,260 / 1,000\", we get:\n    #   - \"initial_guess = 2**pow * 1,260**remainder // 1,000**remainder\".\n    remainder: uint256 = log2x % 3\n    y: uint256 = unsafe_div(\n        unsafe_mul(pow_mod256(2, unsafe_div(log2x, 3)), pow_mod256(1_260, remainder)), pow_mod256(1_000, remainder)\n    )\n\n    # Since we have chosen good initial values for the cube roots, 7 Newton-Raphson\n    # iterations are just sufficient. 6 iterations would lead to non-convergences,\n    # and 8 would be one iteration too many. Without initial values, the iteration\n    # number can be up to 20 or more. The iterations are unrolled. This reduces the\n    # gas cost, but requires more bytecode.\n    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)\n    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)\n    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)\n    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)\n    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)\n    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)\n    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)\n\n    # Since we scaled up, we have to scale down accordingly.\n    if x >= unsafe_mul(unsafe_div(max_value(uint256), 10 ** 36), 10 ** 18):\n        return unsafe_mul(y, 10 ** 12)\n    elif x >= unsafe_div(max_value(uint256), 10 ** 36):\n        return unsafe_mul(y, 10 ** 6)\n\n    return y\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"anonymous":false,"inputs":[{"indexed":false,"name":"admin","type":"address"}],"name":"SetAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"peg_keeper","type":"address"}],"name":"AddPegKeeper","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"peg_keeper","type":"address"}],"name":"RemovePegKeeper","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"rate","type":"uint256"}],"name":"SetRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sigma","type":"int256"}],"name":"SetSigma","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"target_debt_fraction","type":"uint256"}],"name":"SetTargetDebtFraction","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"extra_const","type":"uint256"}],"name":"SetExtraConst","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"debt_ratio_ema_time","type":"uint256"}],"name":"SetDebtRatioEmaTime","type":"event"},{"inputs":[{"name":"admin","type":"address"}],"name":"set_admin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"pk","type":"address"}],"name":"add_peg_keeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"pk","type":"address"}],"name":"remove_peg_keeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rate","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"_for","type":"address"}],"name":"rate","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rate_write","outputs":[{"name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_for","type":"address"}],"name":"rate_write","outputs":[{"name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"rate","type":"uint256"}],"name":"set_rate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"sigma","type":"int256"}],"name":"set_sigma","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"target_debt_fraction","type":"uint256"}],"name":"set_target_debt_fraction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"extra_const","type":"uint256"}],"name":"set_extra_const","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_debt_ratio_ema_time","type":"uint256"}],"name":"set_debt_ratio_ema_time","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"debt_ratio_ema_time","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rate0","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sigma","outputs":[{"name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"target_debt_fraction","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"extra_const","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"uint256"}],"name":"peg_keepers","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_ORACLE","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONTROLLER_FACTORY","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"n_controllers","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"uint256"}],"name":"controllers","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"}],"name":"min_debt_candles","outputs":[{"components":[{"name":"candle0","type":"uint256"},{"name":"candle1","type":"uint256"},{"name":"timestamp","type":"uint256"}],"name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"admin","type":"address"},{"name":"price_oracle","type":"address"},{"name":"controller_factory","type":"address"},{"name":"peg_keepers","type":"address[5]"},{"name":"rate","type":"uint256"},{"name":"sigma","type":"int256"},{"name":"target_debt_fraction","type":"uint256"},{"name":"extra_const","type":"uint256"},{"name":"_debt_ratio_ema_time","type":"uint256"}],"outputs":[],"stateMutability":"nonpayable","type":"constructor"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x00000000000000000000000040907540d8a6c65c637785e8f8b742ae6b0b996800000000000000000000000018672b1b0c623a30089a280ed9256379fb0e4e62000000000000000000000000c9332fdcb1c491dcc683bae86fe3cb70360738bc0000000000000000000000009201da0d97caaaff53f01b2fb56767c7072de340000000000000000000000000fb726f57d251ab5c731e5c64ed4f5f94351ef9f30000000000000000000000003fa20eaa107de08b38a8734063d605d5842fe09c000000000000000000000000338cb2d827112d989a861cde87cd9ffd913a1f9d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000da4d064e0000000000000000000000000000000000000000000000000018de76816d800000000000000000000000000000000000000000000000000003b3823ca998c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bdd80"}