Skip to main content

Pool listing, freezing and LT ramps

A curated list​

Farmenta does not accept positions from just any Uniswap v4 pool. The owner (the admin account) lists pools one by one, after a review. A position from a pool that is not listed is refused, whatever its tokens are.

It works like a pawn shop with a written list of the items it accepts and the terms for each. The list can be tightened or closed for an item at any time, but the shop always lets you redeem what it already holds.

A small example: the owner lists an ETH/USDG pool on the Blue-chip market with max LTV 60%, LT 72% and a debt cap of 200,000 USDG. These are stricter than the tier's loosest values (65%, 75% and 500,000 USDG). Positions from that pool can now be deposited, and loans against them follow those terms.

What the review checks​

The review happens off-chain. Its result is written on-chain by the owner as a token configuration and a pool listing.

Tokens

CheckReason
Not fee-on-transferThe amount received must equal the amount sent
Not rebasingBalances must not change on their own
Not pausable, no blacklistA transfer that can be blocked can block a liquidation
Supply not freely mintableUnlimited minting destroys the collateral value
Decimals recordedDecimals are stored at listing and never read live

The review does not yet screen for per wallet maximums or anti-bot transfer rules, which are common on meme tokens. If such a rule blocks a transfer to you during a liquidation, the leftover fees owed to you stay in the market and your claim to them is lost. See liquidation mechanics.

Pools

CheckRequirement
Total value lockedAt least $50,000
AgeAt least 7 days
Active positionsMore than one
HookPasses the hook permission bit check, or is reviewed by hand and allowlisted
Meme pools onlyThe TwapRecorder holds at least 30 minutes of price history
Meme pools onlyNot listed with real funds until a guard against single transaction price manipulation is in place. See oracle and market risks

A hook reviewed by hand is checked for what it does when liquidity is removed or added (can it revert, does it take a cut, does it charge the caller) and whether the hook itself can be upgraded. If a hook takes a cut on removal, that cut is recorded as the pool's removal haircut. A hook that takes more than 20% is not accepted.

USDG is the deliberate exception

USDG is the asset lenders supply and borrowers borrow, and every accepted pool is quoted in it. Its issuer can freeze addresses and pause the token, which would fail the token checks above. Farmenta cannot exist without USDG, so the rule is handled in code instead: a USDG transfer to a borrower that fails does not block a liquidation. A pause of USDG itself stops every USDG transfer, including repayments, liquidations and lender withdrawals, for as long as it lasts. See oracle and market risks.

These checks are a process, not a contract rule. The contract enforces what is described in the rest of this page.

What a listing stores​

Tokens and pools are configured in the CollateralPolicy contract.

Token configuration​

FieldMeaning
enabledWhether the token may appear in new collateral
tierBlue-chip or Meme
decimalsToken decimals, recorded at listing
priceFeedThe USD price feed of the token. Required for an enabled Blue-chip token.

A pool's tier is not chosen by hand. It is derived from its two tokens: the pool takes the riskier tier of the two. A meme token paired with USDG makes a Meme pool.

Pool listing​

struct Listing {
bool listed;
bool frozen;
Tier tier;
uint16 maxLtvBps;
uint16 ltStartBps;
uint16 ltTargetBps;
uint40 rampStart;
uint40 rampDuration;
uint16 liquidatorBonusBps;
uint16 removeHaircutBps;
uint128 debtCapUsdg;
uint128 minPositionUsd;
}
FieldMeaning
listedThe pool has been listed
frozenThe pool takes no new collateral, no new borrowing and no added liquidity
tierWhich market accepts the pool
maxLtvBpsMax LTV at borrow, in basis points (6500 is 65%)
ltStartBpsLiquidation threshold at the start of a ramp. Equal to the target when there is no ramp.
ltTargetBpsLiquidation threshold at the end of a ramp
rampStartTimestamp at which the ramp begins. Zero when there is no ramp.
rampDurationLength of the ramp in seconds. Zero when there is no ramp.
liquidatorBonusBpsBonus a liquidator receives. The protocol liquidation fee is one tenth of it.
removeHaircutBpsShare a hook takes when liquidity is removed, deducted from every valuation. Zero for hooks that take nothing.
debtCapUsdgMost USDG that can be borrowed against positions of this pool, in USDG with 6 decimals
minPositionUsdSmallest position value accepted, in USD with 18 decimals

Anyone can read a listing with listingOf(poolId), the terms in force with termsOf(poolId), and the current liquidation threshold with effectiveLt(poolId).

Stricter only​

Each tier has a preset. The preset is also the loosest value the contract accepts. A listing may deviate from it in one direction only.

ParameterBlue-chip presetMeme presetA listing may only be
Max LTV65%30%Lower
Liquidation threshold75%40%Lower
Liquidator bonus5%10%Higher
Debt cap per pool500,000 USDG20,000 USDGSmaller
Minimum position value$50$50Higher
Removal haircut (ceiling)20%20%At or below the ceiling

A looser value reverts with LooserThanPreset. A removal haircut above the ceiling reverts with HaircutTooLarge. "Stricter" is measured against the tier preset, not against the pool's previous terms: updateTerms can move a parameter in either direction as long as it stays within the preset.

Some parameters are fixed per tier and cannot be set per pool: the close factor, the reserve factor, the reserve floor, the interest curve and the market debt cap. See risk parameters.

Rules for listing and updateTerms:

  • While the pool accepts new positions, max LTV must be above zero and below LT (NoBorrowingRoom otherwise).
  • A removal haircut above zero is only valid for a hook whose address carries both the afterRemoveLiquidity and the afterRemoveLiquidityReturnsDelta flags. A hook without them cannot take a cut.
  • Raising the removal haircut is only possible while the pool is frozen. Lowering it works at any time.
  • updateTerms clears any active ramp.

Freezing a pool​

setFrozen(poolId, true) freezes a pool. Freezing is how a pool is delisted: it closes the door for new risk and leaves existing loans fully serviceable.

StopsKeeps working
depositCollateral and depositCollateralWithPermitInterest accrual
mintAndDepositrepay
borrowcollectFees
increaseLiquiditydecreaseLiquidity
withdrawCollateral (once debt is zero)
liquidate

Collateral must never be trapped by an operational decision, and switching off liquidation would create the bad debt that freezing is meant to avoid.

LT ramps​

An LT ramp lowers a pool's liquidation threshold gradually, along a schedule that is stored on-chain. It is how Farmenta leaves a pool it no longer wants exposure to: loans are pushed toward repayment or liquidation over a published window instead of all at once.

The effective LT is interpolated linearly at the moment it is read:

before rampStart: effectiveLT = ltStart
after rampStart + rampDuration: effectiveLT = ltTarget
in between:
effectiveLT = ltStart − (ltStart − ltTarget) × elapsed / rampDuration

Example​

A frozen ETH/USDG pool has LT 75%. The owner schedules a ramp to 60% over 10 days.

DayEffective LTBudi's HF (collateral $20,300, debt 12,300 USDG)
075%1.238
469%1.139
863%1.040
1060%0.990

With no price move at all, Budi's loan becomes liquidatable a little before day 10. Because the schedule is public, Budi, keepers and any interface can compute that date in advance and Budi can repay in time.

Rules the contract enforces​

RuleError if broken
rampStart is not in the pastRampStartInThePast
rampDuration is greater than zeroRampDurationIsZero
The target is not above the current effective LTLooserThanPreset
A target at or below max LTV requires a frozen poolRampBelowMaxLtvRequiresFreeze
A pool cannot be unfrozen while max LTV is at or above the ramp targetUnfreezeWouldLeaveNoBorrowingRoom

A ramp always starts from the current effective LT, so a second ramp can never move the threshold back up.

The idea behind the freeze rules: as long as a pool hands out new loans, max LTV stays below LT. Emptying a pool means removing that room, which is only allowed once the pool is frozen. The unfreeze check looks at where the threshold is heading (the target), not where it stands today, so a pool cannot be reopened just before its ramp drops below max LTV.

Parameter changes apply to existing loans​

Changes to a listing apply to existing loans

Changes to a listing apply to loans that already exist. Each change waits two days in the owner's queue before it runs. If the owner lowers LT, through a ramp or in one step with updateTerms, or raises the removal haircut on a frozen pool, the health factor of every loan in that pool falls, and a loan close to its limit can become liquidatable.

The owner's queue and a ramp's schedule are both on-chain, so borrowers can see the change coming. Borrowing below the maximum leaves room for it.

Example: LT is lowered from 75% to 60% while a position is worth $20,300 and owes 12,300 USDG. The health factor drops from 1.238 to 0.990 and the position can be liquidated.

See admin powers.

This power exists so the protocol can step away from a broken oracle, a hook that changes behaviour or a token that collapses.

Owner functions and events​

FunctionEffectEvent
setTokenConfigEnables or disables a token, sets tier, decimals and price feedTokenConfigured
setHookAllowlistAllows or removes a hand reviewed hookHookAllowlisted
listLists a pool with its termsPoolListed
updateTermsRewrites a pool's terms, effective immediatelyPoolTermsUpdated
setFrozenFreezes or unfreezes a poolPoolFrozen
scheduleLtRampSchedules a gradual fall of LTLtRampScheduled

All of them can only be called by the owner. The guardian, an account the owner names for incidents, can also freeze a pool, disable a token and revoke a hook, at once, through freeze, disableToken and revokeHook. It cannot reverse them. Disabling a token does not unlist the pools that contain it. It stops new deposits, liquidity additions and new borrowing for those pools, because both tokens are checked again each time.