Skip to main content

HybridFactoryOwner

The source code of the HybridFactoryOwner.vy contract can be found on GitHub. The contract is written with Vyper version 0.4.3.

Overview

HybridFactoryOwner is the address held as Factory.admin. The DAO does not call Factory.set_admin / LT.set_rate directly; it calls the equivalent wrapper on HybridFactoryOwner, and the wrapper forwards. Three reasons:

  1. One ACL surface. Every privileged call checks msg.sender == ADMIN. The Factory and its LT instances never need their own DAO logic.
  2. Allowlist for stablecoin allocators. limit_setters grants non-admin contracts (notably each HybridVault) permission to call lt_allocate_stablecoins with non-zero limits, without giving them broader admin rights.
  3. Permissionless deallocation of disabled LTs. When the admin disables a market via lt_allocate_stablecoins(lt, 0), the disabled_lts[lt] flag flips. After that, anyone can pull stablecoins out of that market (down to a 75% safety floor on remaining reserves) — useful for winding down without DAO-vote latency.

For market discovery, integrators read the Factory directly. They only need this contract when they are operating inside a HybridVault or running governance tooling.


Immutable variables

NameTypeNotes
ADMINaddressDAO / multisig that owns this proxy. Never changes after deploy.
FACTORYFactoryThe YB Factory this proxy controls. Held as Factory.admin.
STABLECOINIERC20crvUSD, cached from factory.STABLECOIN() at deploy.

Storage

NameTypeDescription
disabled_ltsHashMap[LT, bool]Flag set by ADMIN when an LT is wound down (lt_allocate_stablecoins(lt, 0)). Once true, anyone can drain the market's allocation down to safe reserves. LTMigrator refuses to migrate INTO a disabled LT.
limit_settersHashMap[address, bool]Allowlist of non-admin contracts that may call lt_allocate_stablecoins(lt, limit) with limit > 0. HybridVault instances are added here so they can size their own stablecoin allocation per deposit.

Events

SetLimitSetter — emitted by set_limit_setter

  • setter (address) — address whose privilege changed
  • enabled (bool) — true to grant, false to revoke

Privileged LT controls

All require msg.sender == ADMIN.

FunctionEffect
lt_set_rate(lt, rate)Forwards to LT.set_rate(rate). Changes the borrow / refuel rate on the AMM.
lt_set_amm_fee(lt, fee)Forwards to LT.set_amm_fee(fee). Bounded by AMM.MAX_FEE (10%).
lt_set_killed(lt, is_killed)Kill or unkill the market via LT.set_killed. Killed markets force the emergency_withdraw exit path.
lt_distribute_borrower_fees(lt, discount)Forwards to LT.distribute_borrower_fees(discount). Anyone can call the default-discount variant directly on LT; this wrapper exists so admin can pass a non-default discount.

Stablecoin allocation

@external
def lt_allocate_stablecoins(lt: LT, limit: uint256 = max_value(uint256))

Three call patterns:

CallerlimitBehaviour
ADMIN> 0Sets LT.stablecoin_allocation to limit, clears disabled_lts[lt].
limit_setters[caller] == True> 0Same as above. This is the path HybridVaults use to size allocation during deposits.
ADMIN0Flips disabled_lts[lt] = True. Does not change the LT's allocation directly — that is the next step.
Anyone0, disabled_lts[lt] == TrueReads LT.amm.value_oracle().value, computes safe_limit = value × 3 / 4, and shrinks LT.stablecoin_allocation down to that floor (or available_limit if smaller). Reverts "Not enough reserves" if available_limit is below safe_limit.
Anyone, disabled_lts[lt] == False, limit == 0Reverts "Not disabled".
Anyone else, limit > 0Reverts "Access".

The 75% floor is the same conservative bound used internally by LT.allocate_stablecoins when deflating. It guarantees that even after permissionless deallocation, the AMM still holds three-quarters of its oracle-priced collateral value as stablecoin reserves.

Factory passthroughs

All require msg.sender == ADMIN. Each is a thin one-line forward.

FunctionForwards to
transfer_ownership_back()FACTORY.set_admin(ADMIN, FACTORY.emergency_admin()) — gives admin role back to the DAO directly, bypassing this proxy.
add_market(pool, fee, rate, debt_ceiling)FACTORY.add_market(...)
set_fee_receiver(addr)FACTORY.set_fee_receiver(addr)
set_implementations(amm, lt, virtual_pool, price_oracle, staker)FACTORY.set_implementations(...)
set_min_admin_fee(value)FACTORY.set_min_admin_fee(value)
fill_staker_vpool(i)FACTORY.fill_staker_vpool(i)
set_allocator(allocator, amount)FACTORY.set_allocator(...)
set_agg(agg)FACTORY.set_agg(agg)
set_flash(flash)FACTORY.set_flash(flash)

Limit-setter management

@external
def set_limit_setter(setter: address, enabled: bool)

Only ADMIN. Toggles limit_setters[setter]. Emits SetLimitSetter.

When the HybridVaultFactory deploys a new HybridVault, the DAO is expected to add the vault to limit_setters so it can call lt_allocate_stablecoins during deposit. Revoking the flag freezes the vault's ability to grow stablecoin allocation on a market.

Public views

FunctionReturns
lt_in_factory(lt)True if STABLECOIN.allowance(FACTORY, lt) > 0 — a stand-in check for "factory has approved this LT to spend its crvUSD," used by LTMigrator and by HybridVaults before they route deposits.
lt_needs_withdraw(lt)Quote: number of yb-LP shares the holder would need to withdraw to bring available_limit = lp_price × collateral_amount back down to the LT's stablecoin_allocated. Returns 0 if no withdrawal is needed.

Common revert strings

StringCause
AccessCaller is not ADMIN, or (for lt_allocate_stablecoins with limit > 0) not in limit_setters.
Not disabledPermissionless lt_allocate_stablecoins(lt, 0) called but the LT was never flagged for wind-down.
Not enough reservesPermissionless deallocation attempt would leave the AMM below the 75% safe floor of oracle-priced collateral value.
  • Core: Factory — the contract owned by this proxy.
  • Core: LT — receives all the lt_* forwards.
  • Core: HybridVault — typical limit_setter and the consumer of lt_allocate_stablecoins from non-admin callers.
  • Core: LTMigrator — reads lt_in_factory and disabled_lts before routing migrations.
  • Core: MigrationFactoryOwner — earlier admin-proxy variant without the limit_setters and lt_distribute_borrower_fees surface.