SurplusSplitter¶
Routes skimmed TARE surplus from the engine to sTARE (senior) and CoilMakerStrategy (emission slice). Installed as engine savings_vault.
Source: TARE-Stablecoin/src/SurplusSplitter.vy (Vyper 0.4.3)
Concept guide: SurplusSplitter protocol page
Wired by: TareEngine set_savings_vault · distribute_to_savings
Implementation overview¶
- Engine skim receiver — engine calls
distribute_to_savingswhen surplus exceedssurplus_buffer_target; TARE lands here when this contract issavings_vault. - Senior-first —
split()sends majority to immutableSAVINGS(sTARE); at mostemission_bps(≤30%) toemission_sink. - No-op until configured — sink unset or
emission_bps == 0→ 100% to sTARE (same as wiring sTARE directly). - FLYWHEEL 2.0 —
emission_sinkshould be CoilMakerStrategy (not bare MultiStrategyVault).
flowchart LR
Engine[TareEngine] -->|skim TARE| SS[SurplusSplitter]
SS -->|senior slice| sTARE[sTARE vault]
SS -->|emission_bps| CMS[CoilMakerStrategy]
Immutables¶
| Name | Role |
|---|---|
TARE |
Stablecoin routed |
SAVINGS |
sTARE vault — senior claim, never redirectable |
Constants¶
| Name | Value | Role |
|---|---|---|
MAX_BPS |
10_000 | Basis-point denominator |
MAX_EMISSION_BPS |
3_000 | Hard cap — savings always ≥70% of skim |
Events¶
| Event | When |
|---|---|
EmissionSinkSet |
Owner sets/clears emission sink |
EmissionBpsSet |
Owner updates emission rate |
SurplusSplit |
split() routes balance |
Admin¶
set_emission_sink¶
SurplusSplitter.set_emission_sink(_sink)
Set address receiving emission slice from split(). Pass empty(address) to disable emissions (100% → sTARE).
| Param | Type | Description |
|---|---|---|
_sink |
address |
CoilMakerStrategy in FLYWHEEL 2.0; empty = all to savings |
Returns / state: Updates emission_sink storage.
Access: owner only.
Events: EmissionSinkSet(sink).
Source (TARE-Stablecoin/src/SurplusSplitter.vy:111-120):
@external
def set_emission_sink(_sink: address):
ow._check_owner()
self.emission_sink = _sink
log EmissionSinkSet(sink=_sink)
Example:
splitter.set_emission_sink(coil_maker_strategy)
splitter.set_emission_sink("0x0000000000000000000000000000000000000000") # disable
Cross-links: set_emission_bps · split · sTARE API
set_emission_bps¶
SurplusSplitter.set_emission_bps(_bps)
Set emission slice in basis points. Capped at MAX_EMISSION_BPS (3000 = 30%) so savings always get ≥70%.
| Param | Type | Description |
|---|---|---|
_bps |
uint256 |
Emission share of skim (0–3000 bps) |
Returns / state: Updates emission_bps storage. No effect until emission_sink is set and split() runs.
Access: owner only. Reverts if _bps > MAX_EMISSION_BPS.
Events: EmissionBpsSet(bps).
Source (TARE-Stablecoin/src/SurplusSplitter.vy:123-132):
@external
def set_emission_bps(_bps: uint256):
ow._check_owner()
assert _bps <= MAX_EMISSION_BPS, "SurplusSplitter: bps > cap"
self.emission_bps = _bps
log EmissionBpsSet(bps=_bps)
Example:
Cross-links: set_emission_sink · split
Split¶
split¶
SurplusSplitter.split() -> (uint256, uint256)
Permissionless. Forward contract TARE balance: emission slice → emission_sink, remainder → SAVINGS (sTARE). No-op on zero balance.
Returns: (to_savings, to_emissions) — amounts transferred this call.
Access: Any caller (@nonreentrant). Senior slice transferred first.
Events: SurplusSplit(caller, to_savings, to_emissions).
Source (TARE-Stablecoin/src/SurplusSplitter.vy:139-171):
@external
@nonreentrant
def split() -> (uint256, uint256):
bal: uint256 = staticcall TARE.balanceOf(self)
if bal == 0:
return (0, 0)
sink: address = self.emission_sink
to_emissions: uint256 = 0
if sink != empty(address):
to_emissions = bal * self.emission_bps // MAX_BPS
to_savings: uint256 = bal - to_emissions
extcall TARE.transfer(SAVINGS, to_savings)
extcall TARE.transfer(sink, to_emissions)
return (to_savings, to_emissions)
Example:
Cross-links: set_emission_sink · set_emission_bps · TareEngine distribute_to_savings · sTARE API