{"file_path":"crvUSDControllerFactory.vy","creation_status":"success","source_code":"# @version 0.3.7\n\"\"\"\n@title crvUSD ControllerFactory\n@author Curve.Fi\n@license Copyright (c) Curve.Fi, 2020-2023 - all rights reserved\n\"\"\"\n\ninterface ERC20:\n    def mint(_to: address, _value: uint256) -> bool: nonpayable\n    def burnFrom(_to: address, _value: uint256) -> bool: nonpayable\n    def balanceOf(_user: address) -> uint256: view\n    def decimals() -> uint256: view\n\ninterface PriceOracle:\n    def price() -> uint256: view\n    def price_w() -> uint256: nonpayable\n\ninterface AMM:\n    def set_admin(_admin: address): nonpayable\n\ninterface Controller:\n    def total_debt() -> uint256: view\n    def minted() -> uint256: view\n    def redeemed() -> uint256: view\n    def collect_fees() -> uint256: nonpayable\n\ninterface MonetaryPolicy:\n    def rate_write() -> uint256: nonpayable\n\n\nevent AddMarket:\n    collateral: indexed(address)\n    controller: address\n    amm: address\n    monetary_policy: address\n    ix: uint256\n\nevent SetDebtCeiling:\n    addr: indexed(address)\n    debt_ceiling: uint256\n\nevent MintForMarket:\n    addr: indexed(address)\n    amount: uint256\n\nevent RemoveFromMarket:\n    addr: indexed(address)\n    amount: uint256\n\nevent SetImplementations:\n    amm: address\n    controller: address\n\nevent SetAdmin:\n    admin: address\n\nevent SetFeeReceiver:\n    fee_receiver: address\n\n\nMAX_CONTROLLERS: constant(uint256) = 50000\nSTABLECOIN: immutable(ERC20)\ncontrollers: public(address[MAX_CONTROLLERS])\namms: public(address[MAX_CONTROLLERS])\nadmin: public(address)\nfee_receiver: public(address)\ncontroller_implementation: public(address)\namm_implementation: public(address)\n\nn_collaterals: public(uint256)\ncollaterals: public(address[MAX_CONTROLLERS])\ncollaterals_index: public(HashMap[address, uint256[1000]])\n\ndebt_ceiling: public(HashMap[address, uint256])\ndebt_ceiling_residual: public(HashMap[address, uint256])\n\n# Limits\nMIN_A: constant(uint256) = 2\nMAX_A: constant(uint256) = 10000\nMIN_FEE: constant(uint256) = 10**6  # 1e-12, still needs to be above 0\nMAX_FEE: constant(uint256) = 10**17  # 10%\nMAX_ADMIN_FEE: constant(uint256) = 10**18  # 100%\nMAX_LOAN_DISCOUNT: constant(uint256) = 5 * 10**17\nMIN_LIQUIDATION_DISCOUNT: constant(uint256) = 10**16\n\nWETH: public(immutable(address))\n\n\n@external\ndef __init__(stablecoin: ERC20,\n             admin: address,\n             fee_receiver: address,\n             weth: address):\n    \"\"\"\n    @notice Factory which creates both controllers and AMMs from blueprints\n    @param stablecoin Stablecoin address\n    @param admin Admin of the factory (ideally DAO)\n    @param fee_receiver Receiver of interest and admin fees\n    @param weth Address of WETH contract address\n    \"\"\"\n    STABLECOIN = stablecoin\n    self.admin = admin\n    self.fee_receiver = fee_receiver\n    WETH = weth\n\n\n@internal\n@pure\ndef ln_int(_x: uint256) -> int256:\n    \"\"\"\n    @notice Logarithm ln() function based on log2. Not very gas-efficient but brief\n    \"\"\"\n    # adapted from: https://medium.com/coinmonks/9aef8515136e\n    # and vyper log implementation\n    # This can be much more optimal but that's not important here\n    x: uint256 = _x\n    res: uint256 = 0\n    for i in range(8):\n        t: uint256 = 2**(7 - i)\n        p: uint256 = 2**t\n        if x >= p * 10**18:\n            x /= p\n            res += t * 10**18\n    d: uint256 = 10**18\n    for i in range(59):  # 18 decimals: math.log2(10**10) == 59.7\n        if (x >= 2 * 10**18):\n            res += d\n            x /= 2\n        x = x * x / 10**18\n        d /= 2\n    # Now res = log2(x)\n    # ln(x) = log2(x) / log2(e)\n    return convert(res * 10**18 / 1442695040888963328, int256)\n## End of low-level math\n\n\n@external\n@view\ndef stablecoin() -> ERC20:\n    return STABLECOIN\n\n\n@internal\ndef _set_debt_ceiling(addr: address, debt_ceiling: uint256, update: bool):\n    \"\"\"\n    @notice Set debt ceiling for a market\n    @param addr Controller address\n    @param debt_ceiling Value for stablecoin debt ceiling\n    @param update Whether to actually update the debt ceiling (False is used for burning the residuals)\n    \"\"\"\n    old_debt_residual: uint256 = self.debt_ceiling_residual[addr]\n\n    if debt_ceiling > old_debt_residual:\n        to_mint: uint256 = debt_ceiling - old_debt_residual\n        STABLECOIN.mint(addr, to_mint)\n        self.debt_ceiling_residual[addr] = debt_ceiling\n        log MintForMarket(addr, to_mint)\n\n    if debt_ceiling < old_debt_residual:\n        diff: uint256 = min(old_debt_residual - debt_ceiling, STABLECOIN.balanceOf(addr))\n        STABLECOIN.burnFrom(addr, diff)\n        self.debt_ceiling_residual[addr] = old_debt_residual - diff\n        log RemoveFromMarket(addr, diff)\n\n    if update:\n        self.debt_ceiling[addr] = debt_ceiling\n        log SetDebtCeiling(addr, debt_ceiling)\n\n\n@external\n@nonreentrant('lock')\ndef add_market(token: address, A: uint256, fee: uint256, admin_fee: uint256,\n               _price_oracle_contract: address,\n               monetary_policy: address, loan_discount: uint256, liquidation_discount: uint256,\n               debt_ceiling: uint256) -> address[2]:\n    \"\"\"\n    @notice Add a new market, creating an AMM and a Controller from a blueprint\n    @param token Collateral token address\n    @param A Amplification coefficient; one band size is 1/A\n    @param fee AMM fee in the market's AMM\n    @param admin_fee AMM admin fee\n    @param _price_oracle_contract Address of price oracle contract for this market\n    @param monetary_policy Monetary policy for this market\n    @param loan_discount Loan discount: allowed to borrow only up to x_down * (1 - loan_discount)\n    @param liquidation_discount Discount which defines a bad liquidation threshold\n    @param debt_ceiling Debt ceiling for this market\n    @return (Controller, AMM)\n    \"\"\"\n    assert msg.sender == self.admin, \"Only admin\"\n    assert A >= MIN_A and A <= MAX_A, \"Wrong A\"\n    assert fee <= MAX_FEE, \"Fee too high\"\n    assert fee >= MIN_FEE, \"Fee too low\"\n    assert admin_fee < MAX_ADMIN_FEE, \"Admin fee too high\"\n    assert liquidation_discount >= MIN_LIQUIDATION_DISCOUNT, \"Liquidation discount too low\"\n    assert loan_discount <= MAX_LOAN_DISCOUNT, \"Loan discount too high\"\n    assert loan_discount > liquidation_discount, \"need loan_discount>liquidation_discount\"\n    MonetaryPolicy(monetary_policy).rate_write()  # Test that MonetaryPolicy has correct ABI\n\n    p: uint256 = PriceOracle(_price_oracle_contract).price()  # This also validates price oracle ABI\n    assert p > 0\n    assert PriceOracle(_price_oracle_contract).price_w() == p\n    A_ratio: uint256 = 10**18 * A / (A - 1)\n\n    amm: address = create_from_blueprint(\n        self.amm_implementation,\n        STABLECOIN.address, 10**(18 - STABLECOIN.decimals()),\n        token, 10**(18 - ERC20(token).decimals()),  # <- This validates ERC20 ABI\n        A, isqrt(A_ratio * 10**18), self.ln_int(A_ratio),\n        p, fee, admin_fee, _price_oracle_contract,\n        code_offset=3)\n    controller: address = create_from_blueprint(\n        self.controller_implementation,\n        token, monetary_policy, loan_discount, liquidation_discount, amm,\n        code_offset=3)\n    AMM(amm).set_admin(controller)\n    self._set_debt_ceiling(controller, debt_ceiling, True)\n\n    N: uint256 = self.n_collaterals\n    self.collaterals[N] = token\n    for i in range(1000):\n        if self.collaterals_index[token][i] == 0:\n            self.collaterals_index[token][i] = 2**128 + N\n            break\n        assert i != 999, \"Too many controllers for same collateral\"\n    self.controllers[N] = controller\n    self.amms[N] = amm\n    self.n_collaterals = N + 1\n\n    log AddMarket(token, controller, amm, monetary_policy, N)\n    return [controller, amm]\n\n\n@external\n@view\ndef total_debt() -> uint256:\n    \"\"\"\n    @notice Sum of all debts across controllers\n    \"\"\"\n    total: uint256 = 0\n    n_collaterals: uint256 = self.n_collaterals\n    for i in range(MAX_CONTROLLERS):\n        if i == n_collaterals:\n            break\n        total += Controller(self.controllers[i]).total_debt()\n    return total\n\n\n@external\n@view\ndef get_controller(collateral: address, i: uint256 = 0) -> address:\n    \"\"\"\n    @notice Get controller address for collateral\n    @param collateral Address of collateral token\n    @param i Iterate over several controllers for collateral if needed\n    \"\"\"\n    return self.controllers[self.collaterals_index[collateral][i] - 2**128]\n\n\n@external\n@view\ndef get_amm(collateral: address, i: uint256 = 0) -> address:\n    \"\"\"\n    @notice Get AMM address for collateral\n    @param collateral Address of collateral token\n    @param i Iterate over several amms for collateral if needed\n    \"\"\"\n    return self.amms[self.collaterals_index[collateral][i] - 2**128]\n\n\n@external\n@nonreentrant('lock')\ndef set_implementations(controller: address, amm: address):\n    \"\"\"\n    @notice Set new implementations (blueprints) for controller and amm. Doesn't change existing ones\n    @param controller Address of the controller blueprint\n    @param amm Address of the AMM blueprint\n    \"\"\"\n    assert msg.sender == self.admin\n    assert controller != empty(address)\n    assert amm != empty(address)\n    self.controller_implementation = controller\n    self.amm_implementation = amm\n    log SetImplementations(amm, controller)\n\n\n@external\n@nonreentrant('lock')\ndef set_admin(admin: address):\n    \"\"\"\n    @notice Set admin of the factory (should end up with DAO)\n    @param admin Address of the admin\n    \"\"\"\n    assert msg.sender == self.admin\n    self.admin = admin\n    log SetAdmin(admin)\n\n\n@external\n@nonreentrant('lock')\ndef set_fee_receiver(fee_receiver: address):\n    \"\"\"\n    @notice Set fee receiver who earns interest (DAO)\n    @param fee_receiver Address of the receiver\n    \"\"\"\n    assert msg.sender == self.admin\n    assert fee_receiver != empty(address)\n    self.fee_receiver = fee_receiver\n    log SetFeeReceiver(fee_receiver)\n\n\n@external\n@nonreentrant('lock')\ndef set_debt_ceiling(_to: address, debt_ceiling: uint256):\n    \"\"\"\n    @notice Set debt ceiling of the address - mint the token amount given for it\n    @param _to Address to allow borrowing for\n    @param debt_ceiling Maximum allowed to be allowed to mint for it\n    \"\"\"\n    assert msg.sender == self.admin\n    self._set_debt_ceiling(_to, debt_ceiling, True)\n\n\n@external\n@nonreentrant('lock')\ndef rug_debt_ceiling(_to: address):\n    \"\"\"\n    @notice Remove stablecoins above the debt ceiling from the address and burn them\n    @param _to Address to remove stablecoins from\n    \"\"\"\n    self._set_debt_ceiling(_to, self.debt_ceiling[_to], False)\n\n\n@external\n@nonreentrant('lock')\ndef collect_fees_above_ceiling(_to: address):\n    \"\"\"\n    @notice If the receiver is the controller - increase the debt ceiling if it's not enough to claim admin fees\n            and claim them\n    @param _to Address of the controller\n    \"\"\"\n    assert msg.sender == self.admin\n    old_debt_residual: uint256 = self.debt_ceiling_residual[_to]\n    assert self.debt_ceiling[_to] > 0 or old_debt_residual > 0\n\n    admin_fees: uint256 = Controller(_to).total_debt() + Controller(_to).redeemed() - Controller(_to).minted()\n    b: uint256 = STABLECOIN.balanceOf(_to)\n    if admin_fees > b:\n        to_mint: uint256 = admin_fees - b\n        STABLECOIN.mint(_to, to_mint)\n        self.debt_ceiling_residual[_to] = old_debt_residual + to_mint\n    Controller(_to).collect_fees()","deployed_bytecode":"0x6003361161000c5761139d565b60003560e01c346117805763e9cbd822811861003e576004361061178057602061179260003960005160405260206040f35b638a82f1fe8118610afe576101243610611780576004358060a01c61178057610160526084358060a01c611780576101805260a4358060a01c611780576101a052600054600214611780576002600055620186a15433181561010057600a6101c0527f4f6e6c792061646d696e000000000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b6002602435101561011257600061011b565b61271060243511155b6101855760076101c0527f57726f6e672041000000000000000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b67016345785d8a000060443511156101fd57600c6101c0527f46656520746f6f206869676800000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b620f4240604435101561027057600b6101c0527f46656520746f6f206c6f770000000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b670de0b6b3a763ffff60643511156102e85760126101c0527f41646d696e2066656520746f6f206869676800000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b662386f26fc1000060e435101561035f57601c6101c0527f4c69717569646174696f6e20646973636f756e7420746f6f206c6f77000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b6706f05b59d3b2000060c43511156103d75760166101c0527f4c6f616e20646973636f756e7420746f6f2068696768000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b60e43560c4351161046d5760276101c0527f6e656564206c6f616e5f646973636f756e743e6c69717569646174696f6e5f646101e0527f6973636f756e7400000000000000000000000000000000000000000000000000610200526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b6101a05163e91f2f4c6101c05260206101c060046101dc6000855af1610498573d600060003e3d6000fd5b60203d10611780576101c050506101805163a035b1fe6101e05260206101e060046101fc845afa6104ce573d600060003e3d6000fd5b60203d10611780576101e09050516101c0526101c05115611780576101c0516101805163ceb7f7596101e05260206101e060046101fc6000855af1610518573d600060003e3d6000fd5b60203d10611780576101e09050511861178057602435670de0b6b3a7640000810281670de0b6b3a764000082041861178057905060243560018103818111611780579050801561178057808204905090506101e052620186a45460206117926000396000516102c0526102c05161042052602061179260003960005163313ce567610220526020610220600461023c845afa6105b9573d600060003e3d6000fd5b60203d10611780576102209050518060120360128111611780579050604d81116117805780600a0a90506102e0526102e05161044052610160516103005261030051610460526101605163313ce567610260526020610260600461027c845afa610628573d600060003e3d6000fd5b60203d10611780576102609050518060120360128111611780579050604d81116117805780600a0a905061032052610320516104805260243561034052610340516104a0526101e051670de0b6b3a7640000810281670de0b6b3a76400008204186117805790508060b57101000000000000000000000000000000000082106106b8578160801c91508060401b90505b690100000000000000000082106106d6578160401c91508060201b90505b6501000000000082106106f0578160201c91508060101b90505b63010000008210610708578160101c91508060081b90505b620100008201810260121c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808304808281188284100218905090509050905061036052610360516104c0526101e05160405261078d6102a06113a3565b6102a05161038052610380516104e0526101c0516103a0526103a051610500526044356103c0526103c051610520526064356103e0526103e05161054052610180516104005261040051610560526101606003823b0359600182126117805781600382863c81810183818561042060045afa5050828201816000f0801561178057905090509050905061020052620186a3546101605161024052610240516102e0526101a05161026052610260516103005260c43561028052610280516103205260e4356102a0526102a05161034052610200516102c0526102c0516103605260a06003823b0359600182126117805781600382863c8181018381856102e060045afa5050828201816000f08015611780579050905090509050610220526102005163e9333fab610240526102205161026052803b15611780576000610240602461025c6000855af16108e5573d600060003e3d6000fd5b5061022051604052610104356060526001608052610901611537565b620186a55461024052610160516102405161c34f811161178057620186a6015560006103e8905b8061026052620249f6610160516020526000526040600020610260516103e781116117805781019050546109b2576102405180700100000000000000000000000000000000017001000000000000000000000000000000008110611780579050620249f6610160516020526000526040600020610260516103e78111611780578101905055610a54565b6103e76102605118610a49576028610280527f546f6f206d616e7920636f6e74726f6c6c65727320666f722073616d6520636f6102a0527f6c6c61746572616c0000000000000000000000000000000000000000000000006102c0526102805061028051806102a001601f826000031636823750506308c379a061024052602061026052601f19601f61028051011660440161025cfd5b600101818118610928575b5050610220516102405161c34f81116117805760010155610200516102405161c34f81116117805761c35101556102405160018101818110611780579050620186a555610160517febbe0dfde9dde641808b7a803882653420f3a5b12bb405d238faed959e1e3aa3610220516102605261020051610280526101a0516102a052610240516102c0526080610260a26102205161026052610200516102805260406102606003600055f35b6331dc3ca88118610b9f5760043610611780576000604052620186a554606052600061c350905b8060805260605160805118610b3957610b97565b60405160805161c34f811161178057600101546331dc3ca860a052602060a0600460bc845afa610b6e573d600060003e3d6000fd5b60203d106117805760a09050518082018281106117805790509050604052600101818118610b25575b505060206040f35b63f44102368118610bbc5760243610611780576000606052610bd6565b636bbd5ec78118610c3a5760443610611780576024356060525b6004358060a01c61178057604052620249f660405160205260005260406000206060516103e78111611780578101905054700100000000000000000000000000000000810381811161178057905061c34f8111611780576001015460805260206080f35b63b12d54608118610c575760243610611780576000606052610c71565b631539838f8118610cd65760443610611780576024356060525b6004358060a01c61178057604052620249f660405160205260005260406000206060516103e78111611780578101905054700100000000000000000000000000000000810381811161178057905061c34f81116117805761c351015460805260206080f35b639af8f23c8118610d785760443610611780576004358060a01c611780576040526024358060a01c61178057606052600054600214611780576002600055620186a15433186117805760405115611780576060511561178057604051620186a355606051620186a4557f1694b0703640754583177bb0c9e8d97e4d163cd89d08ae426ef8cb3f4710954260605160805260405160a05260406080a16003600055005b63e9333fab8118610dee5760243610611780576004358060a01c61178057604052600054600214611780576002600055620186a154331861178057604051620186a1557f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a160405160605260206060a16003600055005b63e41ab7718118610e6c5760243610611780576004358060a01c61178057604052600054600214611780576002600055620186a1543318611780576040511561178057604051620186a2557fffb40bfdfd246e95f543d08d9713c339f1d90fa9265e39b4f562f9011d7c919f60405160605260206060a16003600055005b63b933c50a8118610ec95760443610611780576004358060a01c6117805761016052600054600214611780576002600055620186a154331861178057610160516040526024356060526001608052610ec2611537565b6003600055005b632651990f8118610f2c5760243610611780576004358060a01c611780576101605260005460021461178057600260005561016051604052620249f7610160516020526000526040600020546060526000608052610f25611537565b6003600055005b63df068aba81186111815760243610611780576004358060a01c61178057604052600054600214611780576002600055620186a154331861178057620249f8604051602052600052604060002054606052620249f760405160205260005260406000205415610f9c576001610fa2565b60605115155b15611780576040516331dc3ca860a052602060a0600460bc845afa610fcc573d600060003e3d6000fd5b60203d106117805760a090505160405163e231bff060e052602060e0600460fc845afa610ffe573d600060003e3d6000fd5b60203d106117805760e09050518082018281106117805790509050604051634f02c420610120526020610120600461013c845afa611041573d600060003e3d6000fd5b60203d1061178057610120905051808203828111611780579050905060805260206117926000396000516370a0823160c05260405160e052602060c0602460dc845afa611093573d600060003e3d6000fd5b60203d106117805760c090505160a05260a05160805111156111475760805160a051808203828111611780579050905060c05260206117926000396000516340c10f1960e0526040516101005260c05161012052602060e0604460fc6000855af1611103573d600060003e3d6000fd5b60203d106117805760e0518060011c6117805761014052610140505060605160c0518082018281106117805790509050620249f86040516020526000526040600020555b604051631e0cfcef60c052602060c0600460dc6000855af161116e573d600060003e3d6000fd5b60203d106117805760c050506003600055005b63e94b0dd281186111ad57602436106117805760043561c34f8111611780576001015460405260206040f35b6386a8cdbc81186111da57602436106117805760043561c34f81116117805761c351015460405260206040f35b63f851a44081186111fb576004361061178057620186a15460405260206040f35b63cab4d3db811861121c576004361061178057620186a25460405260206040f35b630275417e811861123d576004361061178057620186a35460405260206040f35b633bc5799f811861125e576004361061178057620186a45460405260206040f35b6312397fa1811861127f576004361061178057620186a55460405260206040f35b6324c1173b81186112ad57602436106117805760043561c34f811161178057620186a6015460405260206040f35b63a736726881186112fa5760443610611780576004358060a01c61178057604052620249f660405160205260005260406000206024356103e7811161178057810190505460605260206060f35b63602b62d481186113375760243610611780576004358060a01c61178057604052620249f760405160205260005260406000205460605260206060f35b63c92696b281186113745760243610611780576004358060a01c61178057604052620249f860405160205260005260406000205460605260206060f35b63ad5c4648811861139b57600436106117805760206117b260003960005160405260206040f35b505b60006000fd5b604051606052600060805260006008905b8060a05260a051806007036007811161178057905060ff8111611780578060020a905060c05260c05160ff8111611780578060020a905060e05260e051670de0b6b3a7640000810281670de0b6b3a7640000820418611780579050606051106114635760605160e0518015611780578082049050905060605260805160c051670de0b6b3a7640000810281670de0b6b3a764000082041861178057905080820182811061178057905090506080525b6001018181186113b4575050670de0b6b3a764000060a0526000603b905b8060c052671bc16d674ec80000606051106114ba5760805160a05180820182811061178057905090506080526060518060011c90506060525b6060516060518082028115838383041417156117805790509050670de0b6b3a76400008104905060605260a0518060011c905060a052600101818118611481575050608051670de0b6b3a7640000810281670de0b6b3a76400008204186117805790506714057b7ef7678100810490508060ff1c61178057815250565b620249f860405160205260005260406000205460a05260a051606051111561160f5760605160a051808203828111611780579050905060c05260206117926000396000516340c10f1960e0526040516101005260c05161012052602060e0604460fc6000855af16115ad573d600060003e3d6000fd5b60203d106117805760e0518060011c61178057610140526101405050606051620249f86040516020526000526040600020556040517fad17aca0dc59a6d96350f71e2732094471c65b5a5cecd8f95b376edcd5534cc960c05160e052602060e0a25b60a05160605110156117305760a051606051808203828111611780579050905060206117926000396000516370a0823160e05260405161010052602060e0602460fc845afa611663573d600060003e3d6000fd5b60203d106117805760e09050518082811882841002189050905060c05260206117926000396000516379cc679060e0526040516101005260c05161012052602060e0604460fc6000855af16116bd573d600060003e3d6000fd5b60203d106117805760e0518060011c6117805761014052610140505060a05160c0518082038281116117805790509050620249f86040516020526000526040600020556040517fb21604369d32a00404a085ea01ab0a3f6b63f8a0ebda770e25695572416d9bcf60c05160e052602060e0a25b6080511561177e57606051620249f76040516020526000526040600020556040517f22d26e5448456e0d2368bca46b2c824717b39390656f1c6314237e11d691e4f260605160c052602060c0a25b565b600080fda165767970657283000307000b000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"paris","libraries":{},"outputSelection":{"crvUSDControllerFactory.vy":["abi","ast","interface","ir","userdoc","devdoc","evm.bytecode.object","evm.bytecode.opcodes","evm.deployedBytecode.object","evm.deployedBytecode.opcodes","evm.deployedBytecode.sourceMap","evm.methodIdentifiers"]},"search_paths":["."]},"optimization_runs":null,"sourcify_repo_url":null,"decoded_constructor_args":[["0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E",{"name":"stablecoin","type":"address"}],["0xbabe61887f1de2713c6f97e567623453d3C79f67",{"name":"admin","type":"address"}],["0xeCb456EA5365865EbAb8a2661B0c503410e9B347",{"name":"fee_receiver","type":"address"}],["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",{"name":"weth","type":"address"}]],"compiler_version":"0.3.7+commit.6020b8bb","is_verified_via_verifier_alliance":true,"verified_at":"2025-05-26T11:46:15.196216Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x60206118246000396000518060a01c61181f5760405260206118446000396000518060a01c61181f5760605260206118646000396000518060a01c61181f5760805260206118846000396000518060a01c61181f5760a0523461181f5760405161179252606051620186a155608051620186a25560a0516117b25261179261008c610000396117d2610000f36003361161000c5761139d565b60003560e01c346117805763e9cbd822811861003e576004361061178057602061179260003960005160405260206040f35b638a82f1fe8118610afe576101243610611780576004358060a01c61178057610160526084358060a01c611780576101805260a4358060a01c611780576101a052600054600214611780576002600055620186a15433181561010057600a6101c0527f4f6e6c792061646d696e000000000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b6002602435101561011257600061011b565b61271060243511155b6101855760076101c0527f57726f6e672041000000000000000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b67016345785d8a000060443511156101fd57600c6101c0527f46656520746f6f206869676800000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b620f4240604435101561027057600b6101c0527f46656520746f6f206c6f770000000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b670de0b6b3a763ffff60643511156102e85760126101c0527f41646d696e2066656520746f6f206869676800000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b662386f26fc1000060e435101561035f57601c6101c0527f4c69717569646174696f6e20646973636f756e7420746f6f206c6f77000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b6706f05b59d3b2000060c43511156103d75760166101c0527f4c6f616e20646973636f756e7420746f6f2068696768000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b60e43560c4351161046d5760276101c0527f6e656564206c6f616e5f646973636f756e743e6c69717569646174696f6e5f646101e0527f6973636f756e7400000000000000000000000000000000000000000000000000610200526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b6101a05163e91f2f4c6101c05260206101c060046101dc6000855af1610498573d600060003e3d6000fd5b60203d10611780576101c050506101805163a035b1fe6101e05260206101e060046101fc845afa6104ce573d600060003e3d6000fd5b60203d10611780576101e09050516101c0526101c05115611780576101c0516101805163ceb7f7596101e05260206101e060046101fc6000855af1610518573d600060003e3d6000fd5b60203d10611780576101e09050511861178057602435670de0b6b3a7640000810281670de0b6b3a764000082041861178057905060243560018103818111611780579050801561178057808204905090506101e052620186a45460206117926000396000516102c0526102c05161042052602061179260003960005163313ce567610220526020610220600461023c845afa6105b9573d600060003e3d6000fd5b60203d10611780576102209050518060120360128111611780579050604d81116117805780600a0a90506102e0526102e05161044052610160516103005261030051610460526101605163313ce567610260526020610260600461027c845afa610628573d600060003e3d6000fd5b60203d10611780576102609050518060120360128111611780579050604d81116117805780600a0a905061032052610320516104805260243561034052610340516104a0526101e051670de0b6b3a7640000810281670de0b6b3a76400008204186117805790508060b57101000000000000000000000000000000000082106106b8578160801c91508060401b90505b690100000000000000000082106106d6578160401c91508060201b90505b6501000000000082106106f0578160201c91508060101b90505b63010000008210610708578160101c91508060081b90505b620100008201810260121c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808304808281188284100218905090509050905061036052610360516104c0526101e05160405261078d6102a06113a3565b6102a05161038052610380516104e0526101c0516103a0526103a051610500526044356103c0526103c051610520526064356103e0526103e05161054052610180516104005261040051610560526101606003823b0359600182126117805781600382863c81810183818561042060045afa5050828201816000f0801561178057905090509050905061020052620186a3546101605161024052610240516102e0526101a05161026052610260516103005260c43561028052610280516103205260e4356102a0526102a05161034052610200516102c0526102c0516103605260a06003823b0359600182126117805781600382863c8181018381856102e060045afa5050828201816000f08015611780579050905090509050610220526102005163e9333fab610240526102205161026052803b15611780576000610240602461025c6000855af16108e5573d600060003e3d6000fd5b5061022051604052610104356060526001608052610901611537565b620186a55461024052610160516102405161c34f811161178057620186a6015560006103e8905b8061026052620249f6610160516020526000526040600020610260516103e781116117805781019050546109b2576102405180700100000000000000000000000000000000017001000000000000000000000000000000008110611780579050620249f6610160516020526000526040600020610260516103e78111611780578101905055610a54565b6103e76102605118610a49576028610280527f546f6f206d616e7920636f6e74726f6c6c65727320666f722073616d6520636f6102a0527f6c6c61746572616c0000000000000000000000000000000000000000000000006102c0526102805061028051806102a001601f826000031636823750506308c379a061024052602061026052601f19601f61028051011660440161025cfd5b600101818118610928575b5050610220516102405161c34f81116117805760010155610200516102405161c34f81116117805761c35101556102405160018101818110611780579050620186a555610160517febbe0dfde9dde641808b7a803882653420f3a5b12bb405d238faed959e1e3aa3610220516102605261020051610280526101a0516102a052610240516102c0526080610260a26102205161026052610200516102805260406102606003600055f35b6331dc3ca88118610b9f5760043610611780576000604052620186a554606052600061c350905b8060805260605160805118610b3957610b97565b60405160805161c34f811161178057600101546331dc3ca860a052602060a0600460bc845afa610b6e573d600060003e3d6000fd5b60203d106117805760a09050518082018281106117805790509050604052600101818118610b25575b505060206040f35b63f44102368118610bbc5760243610611780576000606052610bd6565b636bbd5ec78118610c3a5760443610611780576024356060525b6004358060a01c61178057604052620249f660405160205260005260406000206060516103e78111611780578101905054700100000000000000000000000000000000810381811161178057905061c34f8111611780576001015460805260206080f35b63b12d54608118610c575760243610611780576000606052610c71565b631539838f8118610cd65760443610611780576024356060525b6004358060a01c61178057604052620249f660405160205260005260406000206060516103e78111611780578101905054700100000000000000000000000000000000810381811161178057905061c34f81116117805761c351015460805260206080f35b639af8f23c8118610d785760443610611780576004358060a01c611780576040526024358060a01c61178057606052600054600214611780576002600055620186a15433186117805760405115611780576060511561178057604051620186a355606051620186a4557f1694b0703640754583177bb0c9e8d97e4d163cd89d08ae426ef8cb3f4710954260605160805260405160a05260406080a16003600055005b63e9333fab8118610dee5760243610611780576004358060a01c61178057604052600054600214611780576002600055620186a154331861178057604051620186a1557f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a160405160605260206060a16003600055005b63e41ab7718118610e6c5760243610611780576004358060a01c61178057604052600054600214611780576002600055620186a1543318611780576040511561178057604051620186a2557fffb40bfdfd246e95f543d08d9713c339f1d90fa9265e39b4f562f9011d7c919f60405160605260206060a16003600055005b63b933c50a8118610ec95760443610611780576004358060a01c6117805761016052600054600214611780576002600055620186a154331861178057610160516040526024356060526001608052610ec2611537565b6003600055005b632651990f8118610f2c5760243610611780576004358060a01c611780576101605260005460021461178057600260005561016051604052620249f7610160516020526000526040600020546060526000608052610f25611537565b6003600055005b63df068aba81186111815760243610611780576004358060a01c61178057604052600054600214611780576002600055620186a154331861178057620249f8604051602052600052604060002054606052620249f760405160205260005260406000205415610f9c576001610fa2565b60605115155b15611780576040516331dc3ca860a052602060a0600460bc845afa610fcc573d600060003e3d6000fd5b60203d106117805760a090505160405163e231bff060e052602060e0600460fc845afa610ffe573d600060003e3d6000fd5b60203d106117805760e09050518082018281106117805790509050604051634f02c420610120526020610120600461013c845afa611041573d600060003e3d6000fd5b60203d1061178057610120905051808203828111611780579050905060805260206117926000396000516370a0823160c05260405160e052602060c0602460dc845afa611093573d600060003e3d6000fd5b60203d106117805760c090505160a05260a05160805111156111475760805160a051808203828111611780579050905060c05260206117926000396000516340c10f1960e0526040516101005260c05161012052602060e0604460fc6000855af1611103573d600060003e3d6000fd5b60203d106117805760e0518060011c6117805761014052610140505060605160c0518082018281106117805790509050620249f86040516020526000526040600020555b604051631e0cfcef60c052602060c0600460dc6000855af161116e573d600060003e3d6000fd5b60203d106117805760c050506003600055005b63e94b0dd281186111ad57602436106117805760043561c34f8111611780576001015460405260206040f35b6386a8cdbc81186111da57602436106117805760043561c34f81116117805761c351015460405260206040f35b63f851a44081186111fb576004361061178057620186a15460405260206040f35b63cab4d3db811861121c576004361061178057620186a25460405260206040f35b630275417e811861123d576004361061178057620186a35460405260206040f35b633bc5799f811861125e576004361061178057620186a45460405260206040f35b6312397fa1811861127f576004361061178057620186a55460405260206040f35b6324c1173b81186112ad57602436106117805760043561c34f811161178057620186a6015460405260206040f35b63a736726881186112fa5760443610611780576004358060a01c61178057604052620249f660405160205260005260406000206024356103e7811161178057810190505460605260206060f35b63602b62d481186113375760243610611780576004358060a01c61178057604052620249f760405160205260005260406000205460605260206060f35b63c92696b281186113745760243610611780576004358060a01c61178057604052620249f860405160205260005260406000205460605260206060f35b63ad5c4648811861139b57600436106117805760206117b260003960005160405260206040f35b505b60006000fd5b604051606052600060805260006008905b8060a05260a051806007036007811161178057905060ff8111611780578060020a905060c05260c05160ff8111611780578060020a905060e05260e051670de0b6b3a7640000810281670de0b6b3a7640000820418611780579050606051106114635760605160e0518015611780578082049050905060605260805160c051670de0b6b3a7640000810281670de0b6b3a764000082041861178057905080820182811061178057905090506080525b6001018181186113b4575050670de0b6b3a764000060a0526000603b905b8060c052671bc16d674ec80000606051106114ba5760805160a05180820182811061178057905090506080526060518060011c90506060525b6060516060518082028115838383041417156117805790509050670de0b6b3a76400008104905060605260a0518060011c905060a052600101818118611481575050608051670de0b6b3a7640000810281670de0b6b3a76400008204186117805790506714057b7ef7678100810490508060ff1c61178057815250565b620249f860405160205260005260406000205460a05260a051606051111561160f5760605160a051808203828111611780579050905060c05260206117926000396000516340c10f1960e0526040516101005260c05161012052602060e0604460fc6000855af16115ad573d600060003e3d6000fd5b60203d106117805760e0518060011c61178057610140526101405050606051620249f86040516020526000526040600020556040517fad17aca0dc59a6d96350f71e2732094471c65b5a5cecd8f95b376edcd5534cc960c05160e052602060e0a25b60a05160605110156117305760a051606051808203828111611780579050905060206117926000396000516370a0823160e05260405161010052602060e0602460fc845afa611663573d600060003e3d6000fd5b60203d106117805760e09050518082811882841002189050905060c05260206117926000396000516379cc679060e0526040516101005260c05161012052602060e0604460fc6000855af16116bd573d600060003e3d6000fd5b60203d106117805760e0518060011c6117805761014052610140505060a05160c0518082038281116117805790509050620249f86040516020526000526040600020556040517fb21604369d32a00404a085ea01ab0a3f6b63f8a0ebda770e25695572416d9bcf60c05160e052602060e0a25b6080511561177e57606051620249f76040516020526000526040600020556040517f22d26e5448456e0d2368bca46b2c824717b39390656f1c6314237e11d691e4f260605160c052602060c0a25b565b600080fda165767970657283000307000b005b600080fd000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e000000000000000000000000babe61887f1de2713c6f97e567623453d3c79f67000000000000000000000000ecb456ea5365865ebab8a2661b0c503410e9b347000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","name":"crvUSDControllerFactory","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"vyper","evm_version":"paris","can_be_visualized_via_sol2uml":false,"is_verified_via_sourcify":false,"additional_sources":[],"certified":false,"conflicting_implementations":null,"abi":[{"anonymous":false,"inputs":[{"indexed":true,"name":"collateral","type":"address"},{"indexed":false,"name":"controller","type":"address"},{"indexed":false,"name":"amm","type":"address"},{"indexed":false,"name":"monetary_policy","type":"address"},{"indexed":false,"name":"ix","type":"uint256"}],"name":"AddMarket","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"addr","type":"address"},{"indexed":false,"name":"debt_ceiling","type":"uint256"}],"name":"SetDebtCeiling","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"addr","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"MintForMarket","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"addr","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RemoveFromMarket","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amm","type":"address"},{"indexed":false,"name":"controller","type":"address"}],"name":"SetImplementations","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"admin","type":"address"}],"name":"SetAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"fee_receiver","type":"address"}],"name":"SetFeeReceiver","type":"event"},{"inputs":[{"name":"stablecoin","type":"address"},{"name":"admin","type":"address"},{"name":"fee_receiver","type":"address"},{"name":"weth","type":"address"}],"outputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"stablecoin","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"token","type":"address"},{"name":"A","type":"uint256"},{"name":"fee","type":"uint256"},{"name":"admin_fee","type":"uint256"},{"name":"_price_oracle_contract","type":"address"},{"name":"monetary_policy","type":"address"},{"name":"loan_discount","type":"uint256"},{"name":"liquidation_discount","type":"uint256"},{"name":"debt_ceiling","type":"uint256"}],"name":"add_market","outputs":[{"name":"","type":"address[2]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"total_debt","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"collateral","type":"address"}],"name":"get_controller","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"collateral","type":"address"},{"name":"i","type":"uint256"}],"name":"get_controller","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"collateral","type":"address"}],"name":"get_amm","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"collateral","type":"address"},{"name":"i","type":"uint256"}],"name":"get_amm","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"controller","type":"address"},{"name":"amm","type":"address"}],"name":"set_implementations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"admin","type":"address"}],"name":"set_admin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"fee_receiver","type":"address"}],"name":"set_fee_receiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_to","type":"address"},{"name":"debt_ceiling","type":"uint256"}],"name":"set_debt_ceiling","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_to","type":"address"}],"name":"rug_debt_ceiling","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_to","type":"address"}],"name":"collect_fees_above_ceiling","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"arg0","type":"uint256"}],"name":"controllers","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"uint256"}],"name":"amms","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee_receiver","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller_implementation","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amm_implementation","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"n_collaterals","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"uint256"}],"name":"collaterals","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"uint256"}],"name":"collaterals_index","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"}],"name":"debt_ceiling","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"}],"name":"debt_ceiling_residual","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"0x000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e000000000000000000000000babe61887f1de2713c6f97e567623453d3c79f67000000000000000000000000ecb456ea5365865ebab8a2661b0c503410e9b347000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"}