Skip to content

TareEngine

Collateralized debt position (CDP) engine for the TARE stablecoin. Users deposit registered collateral, mint TARE against it, and repay to withdraw. Liquidators close unsafe positions; stability fees accrue into the surplus buffer.

Source: TARE-Stablecoin/src/tare_engine.vy (Vyper 0.4.3)

Sepolia deployment: 0xC9A5e6eD510030fB84E9600440e7062D152489e0address book

Concept guide: TareEngine protocol page

Implementation overview

  • Collateral registry — up to MAX_COLLATERAL (16) assets via add_collateral; not hard-coded WETH/WBTC slots.
  • Oracles — primary + optional fallback Chainlink feeds per asset; pricing via oracle_lib._get_price.
  • Health factor — risk-weighted: each asset contributes value × liquidation_threshold / 100. Liquidatable when HF < 1e18.
  • Surplus buffer — TARE held on-engine; distribute_to_savings skims above surplus_buffer_target into sTARE.
  • Circuit breakerspause blocks new deposits/mints; emergency_shutdown permanently blocks minting. Exits always open.

Events

Event When
CollateralAdded New collateral listed
CollateralDeposited User deposits collateral
CollateralRedeemed User withdraws collateral
SurplusDonated TARE donated to surplus
BadDebtSettled Insolvent position wound down
Paused / EmergencyShutdown Circuit breaker tripped
FeesAccrued Stability fee minted to surplus
SurplusDistributed Surplus sent to sTARE vault
AuctionStarted / AuctionProceeds Dutch auction of seized collateral

Admin

Owner-gated configuration. Owner cannot touch user collateral/debt directly or mint TARE arbitrarily.

add_collateral

TareEngine.add_collateral(token, price_feed, fallback_feed, max_oracle_deviation_bps, liquidation_threshold, token_decimals)

Lists a new collateral asset in the engine registry. Callable once per token; appends to collateral_tokens until MAX_COLLATERAL is reached.

Param Type Description
token address ERC-20 collateral token (plain transfer only — no hooks/rebasing)
price_feed address Primary Chainlink USD price feed
fallback_feed address Secondary feed; empty(address) if none
max_oracle_deviation_bps uint256 Max disagreement between feeds before pricing halts
liquidation_threshold uint256 Percent of this asset's USD value counted toward HF (e.g. 50 → 200% min CR)
token_decimals uint256 Token decimals (1–30) for amount scaling

Returns / state: Writes collateral_config[token] and appends token to collateral_tokens.

Access: owner only (ow._check_owner()).

Events: CollateralAdded(token, price_feed, fallback_feed, liquidation_threshold).

Source (TARE-Stablecoin/src/tare_engine.vy:284-336):

@external
def add_collateral(
    token: address,
    price_feed: address,
    fallback_feed: address,
    max_oracle_deviation_bps: uint256,
    liquidation_threshold: uint256,
    token_decimals: uint256,
):
    ow._check_owner()
    assert token != empty(address), "TareEngine: zero token"
    assert price_feed != empty(address), "TareEngine: zero feed"
    assert not self.collateral_config[token].allowed, "TareEngine: already listed"
    # ... threshold + registry cap checks ...
    self.collateral_config[token] = CollateralConfig(
        allowed=True,
        price_feed=price_feed,
        fallback_feed=fallback_feed,
        max_oracle_deviation_bps=max_oracle_deviation_bps,
        liquidation_threshold=liquidation_threshold,
        token_decimals=token_decimals,
    )
    self.collateral_tokens.append(token)
    log CollateralAdded(...)

Example:

# Owner lists WETH with 50% liquidation threshold (200% min collateral ratio)
engine.add_collateral(
    weth,
    eth_usd_feed,
    empty(address),   # no fallback
    200,              # 2% max feed deviation
    50,               # 50% of value counts toward HF
    18,
)

Cross-links: update_collateral_feed · deposit_collateral · oracle_lib _get_price · Collateral concept guide

update_collateral_feed

TareEngine.update_collateral_feed(token, new_price_feed, new_fallback_feed)

Replaces the primary and/or fallback Chainlink feed for an already-listed collateral. Use when a feed is deprecated or unreliable — no redeploy needed.

Param Type Description
token address Listed collateral token
new_price_feed address New primary USD price feed (required, non-zero)
new_fallback_feed address New fallback feed; empty(address) removes fallback

Returns / state: Updates collateral_config[token].price_feed and .fallback_feed. Does not re-validate feed answers here — oracle_lib._get_price enforces on next pricing call.

Access: owner only.

Events: CollateralFeedUpdated(token, price_feed, fallback_feed).

Source (TARE-Stablecoin/src/tare_engine.vy:339-360):

@external
def update_collateral_feed(
    token: address,
    new_price_feed: address,
    new_fallback_feed: address,
):
    ow._check_owner()
    assert self.collateral_config[token].allowed, "TareEngine: not listed"
    assert new_price_feed != empty(address), "TareEngine: zero feed"
    self.collateral_config[token].price_feed = new_price_feed
    self.collateral_config[token].fallback_feed = new_fallback_feed
    log CollateralFeedUpdated(
        token=token,
        price_feed=new_price_feed,
        fallback_feed=new_fallback_feed,
    )

Example:

# Swap WETH primary feed; drop fallback
engine.update_collateral_feed(weth, new_eth_usd_feed, empty(address))

Cross-links: add_collateral · get_usd_value · oracle_lib API

set_global_debt_ceiling

TareEngine.set_global_debt_ceiling(new_ceiling)

Sets the protocol-wide cap on total outstanding TARE debt. New mints revert once _total_debt() would exceed this ceiling.

Param Type Description
new_ceiling uint256 Maximum total TARE debt (wei) allowed across all positions

Returns / state: Writes global_debt_ceiling.

Access: owner only.

Events: DebtCeilingSet(ceiling=new_ceiling).

Source (TARE-Stablecoin/src/tare_engine.vy:363-371):

@external
def set_global_debt_ceiling(new_ceiling: uint256):
    ow._check_owner()
    self.global_debt_ceiling = new_ceiling
    log DebtCeilingSet(ceiling=new_ceiling)

Example:

# Cap total system debt at 10M TARE
engine.set_global_debt_ceiling(10_000_000 * 10**18)

Cross-links: mint_tare · total_tare_minted · deposit_and_mint

set_stability_fee

TareEngine.set_stability_fee(new_fee)

Sets the per-second stability fee rate (WAD-scaled). Accrued interest mints into the engine surplus buffer and eventually flows to sTARE via distribute_to_savings.

Param Type Description
new_fee uint256 Per-second fractional rate in WAD; max MAX_STABILITY_FEE (~315% APR cap)

Returns / state: Calls _accrue() at the old rate first (non-retroactive), then writes stability_fee.

Access: owner only.

Events: StabilityFeeSet(old_fee, new_fee).

Source (TARE-Stablecoin/src/tare_engine.vy:374-387):

@external
def set_stability_fee(new_fee: uint256):
    ow._check_owner()
    assert new_fee <= MAX_STABILITY_FEE, "TareEngine: fee too high"
    self._accrue()
    old_fee: uint256 = self.stability_fee
    self.stability_fee = new_fee
    log StabilityFeeSet(old_fee=old_fee, new_fee=new_fee)

Example:

# ~5% APR ≈ 5e16 / SECONDS_PER_YEAR per-second WAD rate (verify against deploy params)
engine.set_stability_fee(1_584_000_000_000_000)  # illustrative; use on-chain value

Cross-links: accrue · distribute_to_savings · set_savings_vault · sTARE API

set_savings_vault

TareEngine.set_savings_vault(vault)

Points distribute_to_savings at the sTARE ERC-4626 vault. Pass empty(address) to disable surplus skims to savers.

Param Type Description
vault address sTARE vault contract, or empty(address) to turn off distributions

Returns / state: Writes savings_vault.

Access: owner only.

Events: SavingsVaultSet(vault=vault).

Source (TARE-Stablecoin/src/tare_engine.vy:390-398):

@external
def set_savings_vault(vault: address):
    ow._check_owner()
    self.savings_vault = vault
    log SavingsVaultSet(vault=vault)

Example:

engine.set_savings_vault(stare_vault_address)
# Disable savings skim (surplus stays on-engine)
engine.set_savings_vault(empty(address))

Cross-links: distribute_to_savings · set_surplus_buffer_target · set_stability_fee · sTARE API

set_surplus_buffer_target

TareEngine.set_surplus_buffer_target(target)

Sets minimum TARE kept in engine surplus before distribute_to_savings skims the excess to sTARE. Acts as bad-debt backstop reserve.

Param Type Description
target uint256 Minimum surplus TARE (wei) retained on-engine before savings skim

Returns / state: Writes surplus_buffer_target. Higher target → more self-insurance, less sTARE yield.

Access: owner only.

Events: SurplusBufferTargetSet(target=target).

Source (TARE-Stablecoin/src/tare_engine.vy:401-409):

@external
def set_surplus_buffer_target(target: uint256):
    ow._check_owner()
    self.surplus_buffer_target = target
    log SurplusBufferTargetSet(target=target)

Example:

# Keep 500k TARE on-engine before skimming to sTARE
engine.set_surplus_buffer_target(500_000 * 10**18)

Cross-links: distribute_to_savings · donate_to_surplus · settle_bad_debt · set_savings_vault

set_auction_house

TareEngine.set_auction_house(house)

Wires the Dutch-auction contract that sells seized collateral for TARE. start_auction forwards collateral to this house via open_lot.

Param Type Description
house address AuctionHouse contract, or empty(address) to disable auctions

Returns / state: Writes auction_house. With empty(address), start_auction reverts; owner can still recover collateral via withdraw_seized.

Access: owner only.

Events: AuctionHouseSet(auction_house=house).

Source (TARE-Stablecoin/src/tare_engine.vy:412-421):

@external
def set_auction_house(house: address):
    ow._check_owner()
    self.auction_house = house
    log AuctionHouseSet(auction_house=house)

Example:

engine.set_auction_house(auction_house_address)

Cross-links: start_auction · absorb_auction_proceeds · withdraw_seized · AuctionHouse API

pause

TareEngine.pause()

Trips the reversible circuit breaker. Blocks new deposit_collateral and mint_tare paths while paused. Redeem, burn, liquidate, and settle stay open.

Param Type Description
No inputs

Returns / state: Sets paused = True.

Access: owner only.

Events: Paused(status=True).

Source (TARE-Stablecoin/src/tare_engine.vy:424-431):

@external
def pause():
    ow._check_owner()
    self.paused = True
    log Paused(status=True)

Example:

engine.pause()  # halt new risk intake

Cross-links: unpause · emergency_shutdown · deposit_collateral · mint_tare

unpause

TareEngine.unpause()

Clears paused and resumes new deposits/mints. Reverts if emergency_shutdown already ran — shutdown is one-way.

Param Type Description
No inputs

Returns / state: Sets paused = False when shutdown is false.

Access: owner only.

Events: Paused(status=False).

Source (TARE-Stablecoin/src/tare_engine.vy:434-443):

@external
def unpause():
    ow._check_owner()
    assert not self.shutdown, "TareEngine: shutdown is final"
    self.paused = False
    log Paused(status=False)

Example:

engine.unpause()  # resume after incident

Cross-links: pause · emergency_shutdown

emergency_shutdown

TareEngine.emergency_shutdown()

One-way kill switch. Permanently blocks new deposits and mints (shutdown = True, also sets paused). Redeem, burn, liquidate, and settle remain available so users can unwind. Cannot be undoneunpause reverts after shutdown.

Param Type Description
No inputs

Returns / state: Sets shutdown = True and paused = True.

Access: owner only.

Events: EmergencyShutdown(by=msg.sender).

Source (TARE-Stablecoin/src/tare_engine.vy:446-456):

@external
def emergency_shutdown():
    ow._check_owner()
    self.shutdown = True
    self.paused = True
    log EmergencyShutdown(by=msg.sender)

Example:

engine.emergency_shutdown()  # final — no new minting ever again

Cross-links: pause · unpause · deposit_collateral · redeem_collateral

pause_and_withdraw

TareEngine.pause_and_withdraw(token_collateral, amount)

Emergency user exit while engine is paused or shut down. Caller withdraws their own collateral even when normal redeem paths may be blocked. Burns TARE debt from caller's wallet first (best-effort, proportional).

Param Type Description
token_collateral address Collateral token to withdraw
amount uint256 Collateral amount (token decimals)

Returns / state: Decrements user_to_token_to_amount_deposited[msg.sender][token]; transfers collateral to msg.sender. If user has debt, burns up to min(debt, user_tare_balance) from caller via TARE.burn_from.

Access: anyone (@nonreentrant) — only own deposited collateral.

Events: CollateralRedeemed(token, _from=msg.sender, _to=msg.sender, amount).

Source (TARE-Stablecoin/src/tare_engine.vy:459-492):

@external
@nonreentrant
def pause_and_withdraw(token_collateral: address, amount: uint256):
    assert amount > 0, "TareEngine: zero amount"
    deposited: uint256 = self.user_to_token_to_amount_deposited[msg.sender][token_collateral]
    assert deposited >= amount, "TareEngine: exceeds deposited"
    self.user_to_token_to_amount_deposited[msg.sender][token_collateral] -= amount
    # ... transfer collateral ...
    if art > 0:
        # burn up to min(debt, user_tare_balance) from msg.sender
        extcall TARE.burn_from(msg.sender, burn_amount)

Example:

# User exits WETH collateral during pause (must hold TARE to cover debt burn)
engine.pause_and_withdraw(weth, 1 * 10**18)

Cross-links: pause · emergency_shutdown · redeem_collateral · burn_tare

migrate_tare_ownership

TareEngine.migrate_tare_ownership(new_engine)

One-way upgrade hook after emergency_shutdown. Grants successor engine TARE minter role and transfers TARE token ownership. Frozen engine keeps positions redeemable; new minting moves to successor on same TARE token.

Param Type Description
new_engine address Successor engine contract; must implement TARE() returning this engine's TARE

Returns / state: TARE.set_minter(new_engine, True) then TARE.transfer_ownership(new_engine). This engine retains its minter flag (inert post-shutdown).

Access: owner only. Requires shutdown == True. Successor must be contract, non-zero, not self, and bound to same TARE.

Events: TareOwnershipMigrated(old_engine=self, new_engine=new_engine).

Source (TARE-Stablecoin/src/tare_engine.vy:495-525):

@external
def migrate_tare_ownership(new_engine: address):
    ow._check_owner()
    assert self.shutdown, "TareEngine: shutdown required"
    assert new_engine != empty(address), "TareEngine: zero engine"
    assert new_engine != self, "TareEngine: self migrate"
    assert new_engine.is_contract, "TareEngine: not a contract"
    assert staticcall IEngineMigratable(new_engine).TARE() == TARE.address, \
        "TareEngine: TARE mismatch"
    extcall TARE.set_minter(new_engine, True)
    extcall TARE.transfer_ownership(new_engine)
    log TareOwnershipMigrated(old_engine=self, new_engine=new_engine)

Example:

# After emergency_shutdown — hand mint rights to v2 engine
engine.migrate_tare_ownership(new_tare_engine_v2)

Cross-links: emergency_shutdown · set_peg_keeper · TareToken API

set_peg_keeper

TareEngine.set_peg_keeper(keeper)

Authorises a PegKeeper contract to mint/burn TARE within its own debt ceiling for peg defense. Revokes minter role from previous keeper.

Param Type Description
keeper address PegKeeper contract, or empty(address) to revoke

Returns / state: Sets peg_keeper. Calls TARE.set_minter(old_keeper, False) then TARE.set_minter(keeper, True) when non-zero.

Access: owner only. Engine owns TARE token — only it can grant minter.

Events: PegKeeperSet(keeper=keeper).

Source (TARE-Stablecoin/src/tare_engine.vy:528-544):

@external
def set_peg_keeper(keeper: address):
    ow._check_owner()
    old_keeper: address = self.peg_keeper
    if old_keeper != empty(address):
        extcall TARE.set_minter(old_keeper, False)
    self.peg_keeper = keeper
    if keeper != empty(address):
        extcall TARE.set_minter(keeper, True)
    log PegKeeperSet(keeper=keeper)

Example:

engine.set_peg_keeper(peg_keeper_address)

Cross-links: PegKeeper API · mint_tare · TareToken API


User flows

Position entrypoints for CDP users. All mutating paths use @nonreentrant where noted.

deposit_collateral

TareEngine.deposit_collateral(token_collateral_address, amount_collateral)

Deposits ERC-20 collateral into caller's position. Pulls tokens via transferFrom. Does not mint TARE — pair with mint_tare or use deposit_and_mint.

Param Type Description
token_collateral_address address Listed collateral token
amount_collateral uint256 Amount to deposit (token decimals)

Returns / state: Increments user_to_token_to_amount_deposited[msg.sender][token]; pulls collateral to engine.

Access: anyone (@nonreentrant). Reverts if paused or token not in registry.

Events: CollateralDeposited(user=msg.sender, token, amount).

Source (TARE-Stablecoin/src/tare_engine.vy:556-562, internal 920-934):

@external
@nonreentrant
def deposit_collateral(token_collateral_address: address, amount_collateral: uint256):
    self._deposit_collateral(token_collateral_address, amount_collateral)

@internal
def _deposit_collateral(token_collateral_address: address, amount_collateral: uint256):
    assert not self.paused, "TareEngine: paused"
    assert self.collateral_config[token_collateral_address].allowed, ...
    self.user_to_token_to_amount_deposited[msg.sender][token_collateral_address] += amount_collateral
    extcall IERC20(token_collateral_address).transferFrom(msg.sender, self, amount_collateral)

Example:

weth.approve(engine, 2 * 10**18)
engine.deposit_collateral(weth, 2 * 10**18)

Cross-links: mint_tare · deposit_and_mint · add_collateral · health_factor

mint_tare

TareEngine.mint_tare(amount_tare_to_mint)

Mints TARE against caller's deposited collateral. Accrues stability fees first, updates normalized debt, checks health factor and global debt ceiling, then mints ERC-20 to msg.sender.

Param Type Description
amount_tare_to_mint uint256 TARE to mint (18 decimals)

Returns / state: Increments user_debt_normalized and total_debt_normalized; mints TARE to caller via TARE.mint.

Access: anyone (@nonreentrant). Reverts if paused, zero amount, debt ceiling exceeded, or HF would break.

Events: None directly (debt change; fee accrual may emit FeesAccrued via _accrue).

Source (TARE-Stablecoin/src/tare_engine.vy:565-572, internal 937-955):

@external
@nonreentrant
def mint_tare(amount_tare_to_mint: uint256):
    self._mint_tare(amount_tare_to_mint)

@internal
def _mint_tare(amount_tare_to_mint: uint256):
    self._accrue()
    assert not self.paused, "TareEngine: paused"
    assert self._total_debt() + amount_tare_to_mint <= self.global_debt_ceiling, ...
    dart: uint256 = amount_tare_to_mint * PRECISION // self.rate_index
    self.user_debt_normalized[msg.sender] += dart
    self.total_debt_normalized += dart
    self._revert_if_health_factor_broken(msg.sender)
    extcall TARE.mint(msg.sender, amount_tare_to_mint)

Example:

engine.deposit_collateral(weth, 3 * 10**18)
engine.mint_tare(2000 * 10**18)  # borrow 2000 TARE

Cross-links: deposit_collateral · burn_tare · health_factor · set_global_debt_ceiling · accrue

accrue

TareEngine.accrue()

Permissionlessly advances stability-fee index and mints accrued interest into engine surplus. Keeper-callable during idle periods; all debt-changing entrypoints also call _accrue internally.

Param Type Description
No inputs

Returns / state: Bumps rate_index and last_accrual_time; mints minted TARE to engine and adds to surplus. No-op if stability_fee == 0, no debt, or block.timestamp <= last_accrual_time.

Access: anyone (no reentrancy guard — read-only on user positions).

Events: FeesAccrued(rate_index, minted_to_surplus, timestamp) when interest minted.

Source (TARE-Stablecoin/src/tare_engine.vy:575-583, internal 985-1024):

@external
def accrue():
    self._accrue()

@internal
def _accrue():
    # growth = rate_index * stability_fee * dt / PRECISION
    # minted = total_debt_normalized * growth / PRECISION
    self.rate_index = new_index
    self.surplus += minted
    extcall TARE.mint(self, minted)
    log FeesAccrued(...)

Example:

# Keeper banks idle interest into surplus
engine.accrue()

Cross-links: set_stability_fee · distribute_to_savings · mint_tare · burn_tare

redeem_collateral

TareEngine.redeem_collateral(token_collateral_address, amount)

Withdraws collateral from caller's position to msg.sender. Reverts if withdrawal would break health factor (position must stay solvent).

Param Type Description
token_collateral_address address Collateral token to withdraw
amount uint256 Amount to redeem (token decimals)

Returns / state: Decrements user_to_token_to_amount_deposited[msg.sender][token]; transfers collateral to caller.

Access: anyone (@nonreentrant) — own position only. Works when paused/shutdown (exit path stays open).

Events: CollateralRedeemed(token, _from=msg.sender, _to=msg.sender, amount).

Source (TARE-Stablecoin/src/tare_engine.vy:586-590, internal 958-968):

@external
@nonreentrant
def redeem_collateral(token_collateral_address: address, amount: uint256):
    self._redeem_collateral(token_collateral_address, amount, msg.sender, msg.sender)
    self._revert_if_health_factor_broken(msg.sender)

@internal
def _redeem_collateral(...):
    self.user_to_token_to_amount_deposited[_from][token] -= amount
    extcall IERC20(token).transfer(_to, amount)

Example:

engine.redeem_collateral(weth, 5 * 10**17)  # partial withdraw if HF allows

Cross-links: deposit_collateral · burn_tare · health_factor · pause_and_withdraw

deposit_and_mint

TareEngine.deposit_and_mint(token_collateral, amount_collateral, amount_tare)

Atomic open/increase position: deposit collateral then mint TARE in one tx. Same checks as separate calls; saves gas and avoids partial state.

Param Type Description
token_collateral address Collateral token to deposit
amount_collateral uint256 Collateral amount (token decimals)
amount_tare uint256 TARE to mint against new + existing collateral

Returns / state: Runs _deposit_collateral then _mint_tare (accrue, debt update, HF + ceiling checks, mint).

Access: anyone (@nonreentrant). Reverts if paused on deposit/mint leg.

Events: CollateralDeposited + possible FeesAccrued from accrue inside mint.

Source (TARE-Stablecoin/src/tare_engine.vy:593-599):

@external
@nonreentrant
def deposit_and_mint(
    token_collateral: address, amount_collateral: uint256, amount_tare: uint256
):
    self._deposit_collateral(token_collateral, amount_collateral)
    self._mint_tare(amount_tare)

Example:

weth.approve(engine, 5 * 10**18)
engine.deposit_and_mint(weth, 5 * 10**18, 3000 * 10**18)

Cross-links: deposit_collateral · mint_tare · redeem_for_tare

redeem_for_tare

TareEngine.redeem_for_tare(token_collateral, amount_collateral, amount_tare)

Atomic repay + withdraw: burns TARE debt from caller then withdraws collateral. Inverse of deposit_and_mint.

Param Type Description
token_collateral address Collateral token to withdraw
amount_collateral uint256 Collateral amount to redeem
amount_tare uint256 TARE to burn from caller (repay debt)

Returns / state: _burn_tare (accrue, reduce normalized debt, TARE.burn_from) then _redeem_collateral transfer. HF checked after both legs.

Access: anyone (@nonreentrant). Caller must hold amount_tare and have approved engine for burn_from.

Events: CollateralRedeemed; possible FeesAccrued from accrue in burn path.

Source (TARE-Stablecoin/src/tare_engine.vy:602-609):

@external
@nonreentrant
def redeem_for_tare(
    token_collateral: address, amount_collateral: uint256, amount_tare: uint256
):
    self._burn_tare(amount_tare, msg.sender, msg.sender)
    self._redeem_collateral(token_collateral, amount_collateral, msg.sender, msg.sender)
    self._revert_if_health_factor_broken(msg.sender)

Example:

tare.approve(engine, 1000 * 10**18)
engine.redeem_for_tare(weth, 1 * 10**18, 1000 * 10**18)

Cross-links: burn_tare · redeem_collateral · deposit_and_mint

burn_tare

TareEngine.burn_tare(amount)

Repays TARE debt by burning from caller's wallet. Does not withdraw collateral — use redeem_for_tare for combined repay+withdraw.

Param Type Description
amount uint256 TARE to burn (18 decimals)

Returns / state: _accrue() then reduces user_debt_normalized and total_debt_normalized; TARE.burn_from(msg.sender, amount). HF checked after.

Access: anyone (@nonreentrant). Caller must hold TARE and have approved engine.

Events: Possible FeesAccrued from accrue.

Source (TARE-Stablecoin/src/tare_engine.vy:612-616, internal 971-977):

@external
@nonreentrant
def burn_tare(amount: uint256):
    self._burn_tare(amount, msg.sender, msg.sender)
    self._revert_if_health_factor_broken(msg.sender)

@internal
def _burn_tare(amount: uint256, on_behalf_of: address, tare_from: address):
    self._accrue()
    dart: uint256 = amount * PRECISION // self.rate_index
    self.user_debt_normalized[on_behalf_of] -= dart
    self.total_debt_normalized -= dart
    extcall TARE.burn_from(tare_from, amount)

Example:

tare.approve(engine, 500 * 10**18)
engine.burn_tare(500 * 10**18)

Cross-links: mint_tare · redeem_for_tare · redeem_collateral · health_factor


Liquidation & surplus

liquidate

TareEngine.liquidate(collateral, user, debt_to_cover)

Standard bonus liquidation for positions with HF < 1e18. Liquidator burns their TARE to cover victim debt and receives seized collateral plus LIQUIDATION_BONUS (10%).

Param Type Description
collateral address Collateral token to seize from victim
user address Underwater position to liquidate
debt_to_cover uint256 TARE debt amount liquidator repays (18 decimals)

Returns / state: Accrues fees; seizes debt_to_cover worth of collateral + 10% bonus from victim to liquidator; burns debt_to_cover TARE from liquidator against victim's debt. Victim HF must improve; liquidator HF must stay valid.

Access: anyone (@nonreentrant) when victim HF < MIN_HEALTH_FACTOR. Reverts if victim lacks enough collateral for bonus — use settle_bad_debt for deep insolvency.

Events: CollateralRedeemed (seizure transfer); possible FeesAccrued.

Source (TARE-Stablecoin/src/tare_engine.vy:619-654):

@external
@nonreentrant
def liquidate(collateral: address, user: address, debt_to_cover: uint256):
    assert starting_health_factor < MIN_HEALTH_FACTOR, "TareEngine: Health Factor is good"
    token_amount_from_debt_covered: uint256 = self._get_token_amount_from_usd(collateral, debt_to_cover)
    bonus_collateral: uint256 = token_amount_from_debt_covered * LIQUIDATION_BONUS // LIQUIDATION_PRECISION
    self._redeem_collateral(collateral, token_amount_from_debt_covered + bonus_collateral, user, msg.sender)
    self._burn_tare(debt_to_cover, user, msg.sender)
    assert ending_health_factor > starting_health_factor, "TareEngine: Liquidation failed"

Example:

tare.approve(engine, 500 * 10**18)
engine.liquidate(weth, underwater_user, 500 * 10**18)

Cross-links: settle_bad_debt · health_factor · burn_tare · Liquidations concept guide

TareEngine.donate_to_surplus(amount)

Permissionlessly funds engine surplus backstop with circulating TARE. Donated TARE later burned by settle_bad_debt to cover bad debt.

Param Type Description
amount uint256 TARE to donate (18 decimals)

Returns / state: Increments surplus; pulls TARE from caller via transferFrom.

Access: anyone. Caller must approve engine for TARE.

Events: SurplusDonated(donor=msg.sender, amount=amount).

Source (TARE-Stablecoin/src/tare_engine.vy:661-672):

@external
def donate_to_surplus(amount: uint256):
    assert amount > 0, "TareEngine: zero donation"
    self.surplus += amount
    success: bool = extcall IERC20(TARE.address).transferFrom(msg.sender, self, amount)
    assert success, "TareEngine: donation transfer failed"
    log SurplusDonated(donor=msg.sender, amount=amount)

Example:

tare.approve(engine, 10_000 * 10**18)
engine.donate_to_surplus(10_000 * 10**18)

Cross-links: settle_bad_debt · set_surplus_buffer_target · distribute_to_savings · CoilFeeRouter

settle_bad_debt

TareEngine.settle_bad_debt(user)

Winds down insolvent position where collateral value < debt (past profitable liquidation). Permissionless once underwater.

Param Type Description
user address Insolvent position owner

Returns / state: Seizes all user collateral into seized_collateral; clears user debt from accounting; burns min(debt, surplus) TARE from surplus buffer; books remainder to total_bad_debt.

Access: anyone. Reverts if user has no debt or position is solvent (raw_collateral_value >= debt).

Events: BadDebtSettled(user, burned_from_surplus, booked_bad_debt).

Source (TARE-Stablecoin/src/tare_engine.vy:675-722):

@external
def settle_bad_debt(user: address):
    self._accrue()
    debt: uint256 = art * self.rate_index // PRECISION
    assert raw_collateral_value < debt, "TareEngine: position solvent"
    # seize collateral -> seized_collateral
    self.user_debt_normalized[user] = 0
    burn_amount: uint256 = min(debt, self.surplus)
    if burn_amount > 0:
        self.surplus -= burn_amount
        extcall TARE.burn_from(self, burn_amount)
    remainder: uint256 = debt - burn_amount
    if remainder > 0:
        self.total_bad_debt += remainder
    log BadDebtSettled(...)

Example:

engine.settle_bad_debt(insolvent_user)

Cross-links: liquidate · donate_to_surplus · retire_bad_debt · withdraw_seized · start_auction

retire_bad_debt

TareEngine.retire_bad_debt(amount)

Burns surplus TARE to pay down previously booked total_bad_debt. Restores protocol backing once surplus buffer refilled.

Param Type Description
amount uint256 TARE to burn from surplus against bad-debt ledger (18 decimals)

Returns / state: Decrements surplus and total_bad_debt; burns TARE from engine via burn_from.

Access: anyone. Reverts if amount exceeds total_bad_debt or surplus.

Events: BadDebtSettled(user=empty(address), burned_from_surplus=amount, booked_bad_debt=0).

Source (TARE-Stablecoin/src/tare_engine.vy:725-738):

@external
def retire_bad_debt(amount: uint256):
    assert amount > 0, "TareEngine: zero amount"
    assert amount <= self.total_bad_debt, "TareEngine: exceeds bad debt"
    assert amount <= self.surplus, "TareEngine: insufficient surplus"
    self.surplus -= amount
    self.total_bad_debt -= amount
    extcall TARE.burn_from(self, amount)
    log BadDebtSettled(user=empty(address), burned_from_surplus=amount, booked_bad_debt=0)

Example:

# After surplus refilled via donations/auctions
engine.retire_bad_debt(50_000 * 10**18)

Cross-links: settle_bad_debt · donate_to_surplus · absorb_auction_proceeds

distribute_to_savings

TareEngine.distribute_to_savings() -> uint256

Skims surplus above surplus_buffer_target into sTARE vault. Permissionless keeper call; raises sTARE share price.

Param Type Description
No inputs

Returns: uint256 — TARE sent to savings vault (0 if nothing above target).

State: _accrue() first; transfers excess = surplus - surplus_buffer_target to savings_vault; leaves surplus at target.

Access: anyone. Reverts if savings_vault unset.

Events: SurplusDistributed(vault, amount) when excess > 0.

Source (TARE-Stablecoin/src/tare_engine.vy:741-765):

@external
def distribute_to_savings() -> uint256:
    self._accrue()
    vault: address = self.savings_vault
    assert vault != empty(address), "TareEngine: no savings vault"
    if surplus_now <= target:
        return 0
    excess: uint256 = surplus_now - target
    self.surplus = target
    extcall IERC20(TARE.address).transfer(vault, excess)
    log SurplusDistributed(vault=vault, amount=excess)
    return excess

Example:

distributed = engine.distribute_to_savings()

Cross-links: set_savings_vault · set_surplus_buffer_target · accrue · sTARE API

withdraw_seized

TareEngine.withdraw_seized(token, amount, to)

Owner withdraws collateral seized from insolvent positions via settle_bad_debt. Never touches live user deposits.

Param Type Description
token address Seized collateral token
amount uint256 Amount to withdraw (token decimals)
to address Recipient (non-zero)

Returns / state: Decrements seized_collateral[token]; transfers ERC-20 to to.

Access: owner only.

Events: SeizedWithdrawn(token, to, amount).

Source (TARE-Stablecoin/src/tare_engine.vy:768-784):

@external
def withdraw_seized(token: address, amount: uint256, to: address):
    ow._check_owner()
    assert to != empty(address), "TareEngine: zero recipient"
    assert self.seized_collateral[token] >= amount, "TareEngine: exceeds seized"
    self.seized_collateral[token] -= amount
    extcall IERC20(token).transfer(to, amount)
    log SeizedWithdrawn(token=token, to=to, amount=amount)

Example:

engine.withdraw_seized(weth, 10 * 10**18, treasury_address)

Cross-links: settle_bad_debt · start_auction · set_auction_house

start_auction

TareEngine.start_auction(token, amount)

Owner sends seized collateral to AuctionHouse and opens Dutch auction lot. Proceeds return via absorb_auction_proceeds.

Param Type Description
token address Seized collateral token to auction
amount uint256 Collateral amount (token decimals)

Returns / state: Decrements seized_collateral[token]; transfers collateral to auction_house; calls open_lot(token, amount, token_decimals).

Access: owner only. Requires auction_house set.

Events: AuctionStarted(token, auction_house, amount).

Source (TARE-Stablecoin/src/tare_engine.vy:787-808):

@external
def start_auction(token: address, amount: uint256):
    ow._check_owner()
    house: address = self.auction_house
    assert house != empty(address), "TareEngine: no auction house"
    self.seized_collateral[token] -= amount
    extcall IERC20(token).transfer(house, amount)
    extcall IAuctionHouse(house).open_lot(
        token, amount, self.collateral_config[token].token_decimals
    )
    log AuctionStarted(token=token, auction_house=house, amount=amount)

Example:

engine.start_auction(weth, 5 * 10**18)

Cross-links: withdraw_seized · absorb_auction_proceeds · set_auction_house · AuctionHouse API

absorb_auction_proceeds

TareEngine.absorb_auction_proceeds(amount)

Auction-house callback: receives TARE from completed Dutch auction. Refills surplus to target, burns remainder against total_bad_debt, excess stays in surplus.

Param Type Description
amount uint256 TARE proceeds transferred from auction house (18 decimals)

Returns / state: Pulls TARE via transferFrom; tops up surplus to surplus_buffer_target; burns min(leftover, total_bad_debt); any remainder adds to surplus.

Access: auction_house only (msg.sender == self.auction_house).

Events: AuctionProceeds(to_surplus=amount - burned, bad_debt_retired=burned).

Source (TARE-Stablecoin/src/tare_engine.vy:811-847):

@external
def absorb_auction_proceeds(amount: uint256):
    assert msg.sender == self.auction_house, "TareEngine: only auction house"
    extcall IERC20(TARE.address).transferFrom(msg.sender, self, amount)
    # refill surplus to target, then burn against total_bad_debt
    log AuctionProceeds(to_surplus=amount - burned, bad_debt_retired=burned)

Example:

# Called by AuctionHouse after lot settlement — not integrator-facing
auction_house.settle_and_forward_proceeds(...)  # -> engine.absorb_auction_proceeds(amount)

Cross-links: start_auction · retire_bad_debt · distribute_to_savings · AuctionHouse API


Views

Read-only pricing and position queries. All USD values returned in 18-decimal wei (1e18 = $1).

get_usd_value

TareEngine.get_usd_value(collateral_address, amount) -> uint256

Returns USD value of a collateral amount via Chainlink feeds (primary + optional fallback through oracle_lib._get_price).

Param Type Description
collateral_address address Listed collateral token
amount uint256 Token amount (token's native decimals)

Returns: uint256 — USD value in 18-decimal wei.

State: None (view).

Access: anyone (@view). Reverts if token not allowed or oracle unhealthy.

Events: None.

Source (TARE-Stablecoin/src/tare_engine.vy:854-857, internal 1087-1099):

@external
@view
def get_usd_value(collateral_address: address, amount: uint256) -> uint256:
    return self._get_usd_value(collateral_address, amount)

@internal
@view
def _get_usd_value(token: address, amount: uint256) -> uint256:
    price: uint256 = oracle_lib._get_price(cfg.price_feed, cfg.fallback_feed, ...)
    price_18: uint256 = price * ADDITIONAL_FEED_PRECISION  # 8-dec feed -> 1e18
    return (price_18 * amount) // (10 ** cfg.token_decimals)

Example:

usd = engine.get_usd_value(weth, 1 * 10**18)  # ~$3000e18 at $3k/ETH

Cross-links: get_token_amount_from_usd · health_factor · liquidate · oracle_lib API

get_collateral_value_of_user

TareEngine.get_collateral_value_of_user(user, token_collateral) -> uint256

Returns user's deposited balance of a specific collateral token (raw token units, not USD).

Param Type Description
user address Position owner
token_collateral address Collateral token

Returns: uint256 — deposited amount in token's native decimals.

State: None (view).

Access: anyone (@view).

Events: None.

Source (TARE-Stablecoin/src/tare_engine.vy:860-863):

@external
@view
def get_collateral_value_of_user(user: address, token_collateral: address) -> uint256:
    return self.user_to_token_to_amount_deposited[user][token_collateral]

Example:

weth_deposited = engine.get_collateral_value_of_user(user, weth)  # e.g. 2e18
usd = engine.get_usd_value(weth, weth_deposited)  # convert to USD separately

Cross-links: get_account_collateral_value · get_usd_value · deposit_collateral

get_account_collateral_value

TareEngine.get_account_collateral_value(user) -> uint256

Returns total USD value of all collateral deposited by user across every listed token (unweighted — no liquidation threshold applied).

Param Type Description
user address Position owner

Returns: uint256 — sum of _get_usd_value(token, amount) for each collateral with balance > 0, in 18-decimal USD wei.

State: None (view).

Access: anyone (@view).

Events: None.

Source (TARE-Stablecoin/src/tare_engine.vy:866-869, internal 1076-1082):

@external
@view
def get_account_collateral_value(user: address) -> uint256:
    return self._raw_collateral_value(user)

@internal
@view
def _raw_collateral_value(user: address) -> uint256:
    for token: address in self.collateral_tokens:
        amount: uint256 = self.user_to_token_to_amount_deposited[user][token]
        if amount > 0:
            total_collateral_value_usd += self._get_usd_value(token, amount)
    return total_collateral_value_usd

Example:

total_usd = engine.get_account_collateral_value(user)  # raw collateral USD

Cross-links: get_collateral_value_of_user · health_factor · get_usd_value

get_token_amount_from_usd

TareEngine.get_token_amount_from_usd(token, usd_amount_in_wei) -> uint256

Inverse of get_usd_value — converts USD amount to collateral token units at current oracle price.

Param Type Description
token address Listed collateral token
usd_amount_in_wei uint256 USD value in 18-decimal wei

Returns: uint256 — token amount in native decimals.

State: None (view).

Access: anyone (@view). Reverts if token not allowed or oracle unhealthy.

Events: None.

Source (TARE-Stablecoin/src/tare_engine.vy:872-875, internal 1104-1113):

@external
@view
def get_token_amount_from_usd(token: address, usd_amount_in_wei: uint256) -> uint256:
    return self._get_token_amount_from_usd(token, usd_amount_in_wei)

@internal
@view
def _get_token_amount_from_usd(token: address, usd_amount_in_wei: uint256) -> uint256:
    price_18: uint256 = price * ADDITIONAL_FEED_PRECISION
    return (usd_amount_in_wei * (10 ** cfg.token_decimals)) // price_18

Example:

weth_for_1k = engine.get_token_amount_from_usd(weth, 1000 * 10**18)

Cross-links: get_usd_value · liquidate · oracle_lib API

health_factor

TareEngine.health_factor(user) -> uint256

Risk-weighted position health. HF >= 1e18 = solvent; HF < 1e18 = liquidatable.

Param Type Description
user address Position owner

Returns: uint256sum(value_i × threshold_i / 100) × 1e18 / debt. Returns max_uint256 if debt is zero.

State: None (view). Uses accrued debt via _current_debt (normalized debt × rate index).

Access: anyone (@view).

Events: None.

Source (TARE-Stablecoin/src/tare_engine.vy:878-881, internal 1052-1071):

@external
@view
def health_factor(user: address) -> uint256:
    return self._health_factor(user)

@internal
@view
def _health_factor(user: address) -> uint256:
    # HF = sum(value_i * threshold_i / 100) * 1e18 / debt
    adjusted_collateral_usd += (value * threshold) // LIQUIDATION_PRECISION
    return (adjusted_collateral_usd * PRECISION) // debt

Example:

hf = engine.health_factor(user)
liquidatable = hf < 10**18

Cross-links: liquidate · mint_tare · get_account_collateral_value · add_collateral

user_to_tare_minted

TareEngine.user_to_tare_minted(user) -> uint256

Returns user's live TARE debt including accrued stability fees (via rate index).

Param Type Description
user address Position owner

Returns: uint256user_debt_normalized[user] × rate_index / PRECISION (18-decimal TARE wei).

State: None (view). May lag a few seconds of un-banked interest until next accrue() or debt op.

Access: anyone (@view).

Events: None.

Source (TARE-Stablecoin/src/tare_engine.vy:884-892, internal 1029-1030):

@external
@view
def user_to_tare_minted(user: address) -> uint256:
    return self._current_debt(user)

@internal
@view
def _current_debt(user: address) -> uint256:
    return self.user_debt_normalized[user] * self.rate_index // PRECISION

Example:

debt = engine.user_to_tare_minted(user)

Cross-links: total_tare_minted · health_factor · accrue · burn_tare

total_tare_minted

TareEngine.total_tare_minted() -> uint256

Returns protocol-wide live TARE debt (sum of all positions, fee-accrued via rate index).

Param Type Description
No inputs

Returns: uint256total_debt_normalized × rate_index / PRECISION (18-decimal TARE wei).

State: None (view). Same accrual lag caveat as user_to_tare_minted.

Access: anyone (@view).

Events: None.

Source (TARE-Stablecoin/src/tare_engine.vy:895-901, internal 1035-1036):

@external
@view
def total_tare_minted() -> uint256:
    return self._total_debt()

@internal
@view
def _total_debt() -> uint256:
    return self.total_debt_normalized * self.rate_index // PRECISION

Example:

system_debt = engine.total_tare_minted()

Cross-links: user_to_tare_minted · set_global_debt_ceiling · accrue

get_collateral_tokens_length

TareEngine.get_collateral_tokens_length() -> uint256

Returns count of collateral assets currently listed in the registry.

Param Type Description
No inputs

Returns: uint256len(collateral_tokens) (max MAX_COLLATERAL = 16).

State: None (view).

Access: anyone (@view).

Events: None.

Source (TARE-Stablecoin/src/tare_engine.vy:904-907):

@external
@view
def get_collateral_tokens_length() -> uint256:
    return len(self.collateral_tokens)

Example:

n = engine.get_collateral_tokens_length()
for i in range(n):
    # iterate collateral_tokens off-chain via events or indexer
    ...

Cross-links: add_collateral · is_collateral_allowed

is_collateral_allowed

TareEngine.is_collateral_allowed(token) -> bool

Checks whether a token is listed and allowed as collateral.

Param Type Description
token address Collateral token to query

Returns: boolcollateral_config[token].allowed.

State: None (view).

Access: anyone (@view).

Events: None.

Source (TARE-Stablecoin/src/tare_engine.vy:909-912):

@external
@view
def is_collateral_allowed(token: address) -> bool:
    return self.collateral_config[token].allowed

Example:

if engine.is_collateral_allowed(weth):
    engine.deposit_collateral(weth, amount)

Cross-links: add_collateral · get_collateral_tokens_length · deposit_collateral