Stability Fee Treasury
1. Summary
The StabilityFeeTreasury
is meant to allow other contracts or EOAs to pull funds (stability fees) in order to finance their operations. The treasury is set up as a secondaryReceiver
in the TaxCollector
. Anyone can periodically call the contract in order to recompute an optimal amount of fees that should be kept in the treasury and send any additional surplus to the extraSurplusReceiver
.
2. Contract Variables & Functions
Variables
authorizedAccounts[usr: address]
-addAuthorization
/removeAuthorization
- auth mechanismsallowance[receiver: address]
- total withdrawal allowancepulledPerBlock[usr: address
,blockNr: uint256]
- total amount pulled by a user on a specific blocksafeEngine
- address of theSAFEEngine
systemCoin
- system coin address (Coin.sol)coinJoin
- system coin adapter addressextraSurplusReceiver
- address that receives extra unused funds from the treasurytreasuryCapacity
- maximum amount of stability fees should be kept in the treasuryminimumFundsRequired
- minimum amount of stability fees that must be kept in the treasury at all timesexpensesMultiplier
- multiplier for the expenses incurred since the lasttransferSurplusFunds
call. Ensures there's a buffer of funds on top of the expected expenses until the nexttransferSurplusFunds
callsurplusTransferDelay
- delay between twotransferSurplusFunds
callsexpensesAccumulator
- total expenses incurred since treasury deploymentaccumulatorTag
- latest snapshot ofexpensesAccumulator
latestSurplusTransferTime
- last timestamp whentransferSurplusFunds
was calledcontractEnabled
- global settlement flag
Data Structures
Allowance
- struct that specifies the total and the per-block withdrawal allowance for an address. Contains:total
- the total allowance (inRAD
)perBlock
- the per-block allowance (inRAD
)
Modifiers
isAuthorized
**** - checks whether an address is part ofauthorizedAddresses
(and thus can call authed functions).accountNotTreasury
- checks that the receiver account for treasury funds is not the treasury itself
Functions
modifyParameters()
- authorized function for changing treasury parametersdisableContract()
- disable the treasury and transfer all of its funds to theextraSurplusReceiver
joinAllCoins()
- join any ERC20 system coins that the treasury has into internal coin form (SAFEEngine.coinBalance
)getAllowance(account: address)
- get the total and the per-block allowance for a usersetTotalAllowance(account: address
,rad: uint256)
- authorized function that changes the total allowed amount an address can withdraw from the treasurysetPerBlockAllowance(account: address
,rad: uint256)
- authorized function that changes the amount that an address can withdraw from the treasury every blockgiveFunds(account: address
,rad: uint256)
- governance controlled function that transfers stability fees from the treasury to a destination addresstakeFunds(account: address
,rad: uint256)
- governance controlled function that transfers stability fees from a target address to the treasurypullFunds(dstAccount: address
,token: address
,wad: uint256)
- take funds from the treasury. Reverts if the caller is not allowed to withdraw or if their per-block allowance doesn't allow ittransferSurplusFunds()
- recalculate the amount of stability fees that should remain in the treasury and transfer additional funds to theextraSurplusReceiver
Events
AddAuthorization
- emitted when a new address becomes authorized. Contains:account
- the new authorized account
RemoveAuthorization
- emitted when an address is de-authorized. Contains:account
- the address that was de-authorized
ModifyParameters
- emitted when a parameter is updated.DisableContract
- emitted when the contract is disabled.SetTotalAllowance
- emitted when the total allowance for an address is set. Contains:account
- the account whose allowance was changedrad
- the new total allowance for theaccount
SetPerBlockAllowance
- emitted when the per-block allowance for an address is set. Contains:account
- the account whose per-block allowance was changedrad
- the new total allowance for theaccount
GiveFunds
- emitted when governance offers funds to an address. Contains:account
- the account that received fundsrad
- the amount of funds that were givenexpensesAccumulator
- the sum of all the expenses incurred since the contract was deployed
TakeFunds
- emitted when governance calls the treasury to take funds from an address. Contains:account
- the account the treasury takes system coins fromrad
- the amount of (internal) system coins to take (expressed asRAD
)
PullFunds
- emitted when an approved address pulls funds from the treasury. Contains:sender
- themsg.sender
that calledpullFunds
dstAccount
- the address that received fundstoken
- the address of the token being transferred (in this case it's always the address of the ERC20 system coin)rad
- the total amount of internal system coins transferredexpensesAccumulator
- the sum of all the expenses incurred since the contract was deployed
TransferSurplusFunds
- emitted when surplus funds above the optimum amount are sent to the accounting engine. Contains:extraSurplusReceiver
- the address that received the extra fundsfundsToTransfer
- the amount of funds sent
3. Walkthrough
The treasury is funded by stability fees coming from the TaxCollector
or by anyone who is willing to send system coins (either internally or as ERC20 tokens) to it. Governance can also use takeFunds
to transfer internal system coins from a source address to the treasury.\
\
Governance is in charge with setting up authorized addresses that can pullFunds
out of the treasury (if their total or per-block allowance
permits) as well as setting treasury parameters in order to determine the optimum amount of funds that should remain in the contract at any time. We define "optimum" as a multiplier (expensesMultiplier
) of the latest expenses incurred by the treasury since the last transferSurplusFunds
call.
transferSurplusFunds
is the way the treasury recalculates the amount of funds it should keep in reserves and transfers any surplus to the extraSurplusReceiver
. Note that there is a surplusTransferDelay
time delay between recalculating the optimum and transferring surplus out of the contract.
{% hint style="info" %}
Sending Funds to extraSurplusReceiver
or to the Treasury Itself
In case governance wants to send funds to extraSurplusReceiver
using giveFunds
, expensesAccumulator
will not increase. In case an address wants to pullFunds
and send them to the extraSurplusReceiver
, pullFunds
will revert.\
\
pullFunds
will silently fail if the dstAccount
is the treasury contract itself, whereas giveFunds
will revert.
{% endhint %}