FeePool¶
Description¶
Source: FeePool.sol
Architecture¶
Inheritance Graph¶
Related Contracts¶
Details
Proxy
: The fee pool, beingProxyable
, sits behind aCALL
-style proxy for upgradeability.Oikos
: The fee pool needs the Synthetix address for a onlySynthetix modifer for storing a minters issue and burn events to track their debt % of the system.OikosState
: The fee pool retrieves the global issuance ratio, and queries the debt ledger directly from the Synthetix state contract.Synth
: The fee pool, retrieving their addresses from the Oikos contract, directly burns and issues oUSD when transferring fees. Fees are denominated and paid out in oUSD. Synths themselves do not know the fee pool address directly, but ask the fee pool's proxy for its target.FeePoolState
: The fee pool state contract holds the details of each user's most recent issuance events: when they issued and burnt synths, and their value.FeePoolEternalStorage
: A storage contact that holds the last fee withdrawal time for each account.DelegateApprovals
: A storage contract containing addresses to which the right to withdraw fees has been delegated by another account, for example to allow hot wallets to withdraw fees.RewardEscrow
: The contract into which inflationary OKS rewards are paid by the fee pool so that they can be escrowed for a year after being claimed.RewardsDistribution
: This contract, in the guise of therewardsAuthority
, distributes allocations from the inflationary supply to various recipients.Depot
: Allows users to exchange between Synths, OKS, and Ether. The Depot uses the fee pool to know what transfer fees were being incurred on its transfers, although the transfer fee has been nil since before SIP-19.
Libraries¶
- SafeMath for uint
- SafeDecimalMath for uint
Structs¶
FeePeriod
¶
A record for a fee period, when it was opened, and the fees and rewards accrued within it. This information is maintained for the last several fee periods in recentFeePeriods
.
Field | Type | Description |
---|---|---|
feePeriodId | uint |
A serial id for fee periods which is incremented for each new fee period. |
startingDebtIndex | uint |
The length of OikosState.debtLedger at the time this fee period began. |
startTime | uint |
The current timestamp when this fee period began. |
feesToDistribute | uint (18 decimals) |
The total of fees to be distributed in this period, in oUSD. This increases when fees are collected in the current period or when unclaimed fees roll over from the oldest period to the second oldest. See feePaid and closeCurrentPeriod . |
feesClaimed | uint (18 decimals) |
The number of fees that have already been claimed during this period. |
rewardsToDistribute | uint (18 decimals) |
The total of inflationary rewards to be distributed in this period, in OKS. This increases when new rewards are minted by Oikos.mint /rewardsMinted , or when unclaimed rewards roll over from the oldest period to the second oldest (closeCurrentPeriod ). |
rewardsClaimed | uint (18 decimals) |
The quantity of inflationary rewards that have already been claimed during this period. |
Constants¶
FEE_ADDRESS
¶
The address where fees are pooled as oUSD.
Type: address constant public
Value: 0xfeEFEEfeefEeFeefEEFEEfEeFeefEEFeeFEEFEeF
FEE_PERIOD_LENGTH
¶
This is the number of weekly fee periods that are tracked by the smart contracts, hence the length of the recentFeePeriods
array.
This was reduced from 6 to 3 as part of SIP-4, but note the inconsistency with the corresponding constant in FeePoolState
, which cannot be altered.
Type: uint constant public
Value: 3
LAST_FEE_WITHDRAWAL
¶
This string is used as part of a key for accessing account withdrawal timestamps from the eternal storage contract.
This is only used within FeePool.getLastFeeWithdrawal
and FeePool.setLastFeeWithdrawal
, where it is hashed together with the target address to obtain the correct key.
This must have the same value as FeePoolEternalStorage.LAST_FEE_WITHDRAWAL
.
Type: bytes32 constant
Value: "last_fee_withdrawal"
MAX_EXCHANGE_FEE_RATE
¶
exchangeFeeRate
cannot exceed this. Initialised to 10%.
Type: uint constant public
(18 decimals)
Value: 0.1
MAX_FEE_PERIOD_DURATION
¶
The maximum value of feePeriodDuration
.
Type: uint public constant
Value: 60 days
MIN_FEE_PERIOD_DURATION
¶
The minimum value of feePeriodDuration
.
Type: uint public constant
Value: 1 days
TARGET_THRESHOLD
¶
A threshold that allows issuers to be undercollateralised by up to 10%. Users may claim fees if their collateralisation ratio is below the target issuance ratio plus 10%.
This is designed to allow users to have a little slack in case prices move quickly.
Type: uint public
Variables¶
delegates
¶
The address fo the DelegateApprovals
contract, used to allow delegation of fee claims.
Type: DelegateApprovals public
exchangeFeeRate
¶
The fee fraction charged on a currency exchange, between 0 and 0.1.
Type: uint public
(18 decimals)
feePeriodDuration
¶
This is the minimum duration of a single fee period in seconds. In practice they may be slightly longer if closeCurrentFeePeriod
is not called immediately at the earliest valid moment.
Its value is one week, but it may be between MIN_FEE_PERIOD_DURATION
and MAX_FEE_PERIOD_DURATION
(1 to 60 days).
Type: uint public
feePoolEternalStorage
¶
The FeePoolEternalStorage
key-value store that holds account last withdrawal times.
Type: FeePoolEternalStorage public
feePoolState
¶
The FeePoolState
contract associated with this fee pool, which holds historical issuance data for the last several periods.
Type: FeePoolState public
rewardsAuthority
¶
The address with the authority to distribute rewards, which is the RewardsDistribution
contract.
Type: address public
rewardEscrow
¶
The RewardEscrow
instance which holds inflationary rewards.
Type: RewardEscrow public
recentFeePeriods
¶
Stores fee period information for the last three weeks, from newest to olders.
recentFeePeriods[0]
is always the current fee period, which is modified by ongoing issuance and fee activity. Fees cannot be claimed from the current period, only from the closed periods at indexes 1
and 2
.
Type: FeePeriod[FEE_PERIOD_LENGTH] public
oikos
¶
The main Oikos
contract.
Type: Oikos public
oikosState
¶
The associated OikosState
contract.
Type: OikosState public
Constructor¶
This initialises the various state contract addresses the fee pool knows about, along with its inherited SelfDestructible
, Proxyable
, and LimitedSetup
instances.
This constructor also begins the first fee period, as it initialises the first fee period id to 1, and the first fee period start time to the construction time.
Details
Signature
constructor(address _proxy, address _owner, Oikos _oikos, FeePoolState _feePoolState, FeePoolEternalStorage _feePoolEternalStorage, ISynthetixState _oikosState, ISynthetixEscrow _rewardEscrow, address _rewardsAuthority, uint _exchangeFeeRate) public
Superconstructors
Preconditions
_exchangeFeeRate
must be no greater thanMAX_EXCHANGE_FEE_RATE
.
Views¶
amountReceivedFromTransfer
¶
Computes the number of Synths received by the recipient if a certain quantity is sent.
As of SIP-19, this is just the identity function, since there are no longer any transfer fees. It is only used by the Depot
contract.
Details
Signature
amountReceivedFromTransfer(uint value) external view returns (uint)
amountReceivedFromExchange
¶
Computes the quantity received if a quantity of Synths is exchanged into another flavour. The amount received is the quantity sent minus the exchange fee, as per the logic in Oikos._internalExchange
.
Details
Signature
amountReceivedFromExchange(uint value) external view returns (uint)
effectiveDebtRatioForPeriod
¶
Given an account and an index into recentFeePeriods
, this function computes the percentage of total debt ownership of the account at the end of that period.
This uses _effectiveDebtRatioForPeriod
, where the start index and ownership percentage are computed with FeePoolState.applicableIssuanceData
, and the end index is one before the beginnging of the next period. Hence this function disallows querying the debt for the current period.
In principle a future version could support the current fee period by using the last debt ledger entry as the end index.
Details
Signature
effectiveDebtRatioForPeriod(address account, uint period) external view returns (uint)
Preconditions
period
must not be 0, as the current fee period has not closed.period
must not exceedFEE_PERIOD_LENGTH
.
exchangeFeeIncurred
¶
Returns the fee charged on an exchange of a certain quantity of Synths into another flavour. This is simply the input multiplied by exchangeFeeRate
.
Details
Signature
exchangeFeeIncurred(uint value) public view returns (uint)
feesAvailable
¶
Return the total of fees and rewards available to be withdrawn by this account. The result is reported as a [fees, rewards]
pair denominated in the requested Synth flavour and OKS, respectively.
This is the total of fees accrued in completed periods, so is simply the the sum over an account's feesByPeriod
not including the current period.
Details
Signature
feesAvailable(address account, bytes32 currencyKey) public view returns (uint, uint)
feesByPeriod
¶
Returns an array of FEE_PERIOD_LENGTH
[fees, rewards]
pairs owed to an account for each recent fee period (including the current one). Fees are denominated in oUSD and rewards in OKS.
To compute this, for each period from oldest to newest, find the latest issuance event this account performed before the close of this period, and use it to derive the owed fees and rewards for that period.
Note that a single issuance event can result in fees accruing for several fee periods, if the issuer does not claim their fees in one or more periods.
Periods where the user has already withdrawn since that period closed are skipped, producing [0,0]
entries.
Details
Signature
feesByPeriod(address account) public view returns (uint[2][FEE_PERIOD_LENGTH] memory results)
feesClaimable
¶
This is a predicate, returning true iff a particular account is permitted to claim any fees it has accrued.
A account is able to claim fees if its collateralisation ratio is less than 110% of the global issuance ratio.
Details
Signature
feesClaimable(address account) public view returns (bool)
getLastFeeWithdrawal
¶
Returns from FeePoolEternalStorage
the id of the fee period during which the given address last withdrew fees.
Details
Signature
getLastFeeWithdrawal(address _claimingAddress) public view returns (uint)
getPenaltyThresholdRatio
¶
Returns the collateralisation level a user can reach before they cannot claim fees. This is simply OikosState.issuanceRatio *
(1 + TARGET_THRESHOLD)
. The result is returned as a 18-decimal fixed point number.
Details
Signature
getPenaltyThresholdRatio() public view returns (uint)
totalFeesAvailable
¶
Computes the total fees available to be withdrawn, valued in terms of currencyKey
. This simply sums the unclaimed fees over recentFeePeriods
except those from the current period, because they cannot yet be claimed.
Details
Signature
totalFeesAvailable(bytes32 currencyKey) external view returns (uint)
totalRewardsAvailable
¶
Computes the total OKS rewards available to be withdrawn. This simply sums the unclaimed rewards over recentFeePeriods
except those from the current period, because they cannot yet be claimed.
Details
Signature
totalRewardsAvailable() external view returns (uint)
Mutative Functions¶
approveClaimOnBehalf
¶
Approves an account as a fee claimant for the sender in the DelegateApprovals
contract.
Details
Signature
approveClaimOnBehalf(address account) public
Modifiers
Preconditions
- The
delegates
address must not be zero. account
must not be zero.
claimFees
¶
The message sender claims their fees in oUSD
.
This is equivalent to _claimFees(messageSender)
.
claimOnBehalf
¶
The message sender claims fees in oUSD
for a specified address; the funds are remitted to that address, and not to the sender.
This function first checks with the DelegateApprovals
contract that the sender is approved to claim fees on behalf of the specified address, but is otherwise equivalent to _claimFees(claimingForAddress)
.
Details
Signature
claimOnBehalf(address claimingForAddress) external returns (bool)
Modifiers
Preconditions
messageSender
must be an approved delegate ofclaimingForAddress
.
closeCurrentFeePeriod
¶
If the current fee period has been open for longer than feePeriodDuration
, then anyone may call this function to close it and open a new one.
The new fee period is added to the beginning of the recentFeePeriods
list, and the last one is discarded. Any unclaimed fees from the last fee period roll over into the penultimate fee period.
The new fee period's feePeriodId
is the previous id incremented by 1, and its startingDebtIndex
is the length of OikosState.debtLedger
at the time the fee period rolls over. Note that before a new minting event occurs this index will be one past the end of the ledger.
Details
Signature
closeCurrentFeePeriod() external
Preconditions
- The start time of the current fee period must have been at least
feePeriodDuration
seconds in the past.
Emits
removeClaimOnBehalf
¶
Disapproves an account as a fee claimant for the sender in the DelegateApprovals
contract.
Details
Signature
removeClaimOnBehalf(address account) public
Modifiers
Preconditions
- The
delegates
address must not be zero.
Owner Functions¶
appendVestingEntry
¶
Allows the contract owner to escrow OKS rewards for particular accounts. The rewards are escrowed for one year.
The OKS is deposited into the RewardEscrow
contract from the sender using the ERC20 transferFrom function. The tokens are then escrowed on behalf of the targeted account with RewardEscrow.appendVestingEntry
.
Details
Signature
appendVestingEntry(address account, uint quantity) public
Modifiers
importFeePeriod
¶
During the setup period, allowed the contract owner to set a particular fee period entry in recentFeePeriods
in order to migrate from a previous contract version.
Details
Signature
importFeePeriod(uint feePeriodIndex, uint feePeriodId, uint startingDebtIndex, uint startTime, uint feesToDistribute, uint feesClaimed, uint rewardsToDistribute, uint rewardsClaimed) public
Modifiers
setDelegateApprovals
¶
Allows the contract owner to set the DelegateApprovals
contract address.
Details
Signature
setDelegateApprovals(DelegateApprovals _delegates) external
Modifiers
setExchangeFeeRate
¶
Allows the contract owner to set the exchange fee rate.
Details
Signature
setExchangeFeeRate(uint _exchangeFeeRate) external
Modifiers
setFeePeriodDuration
¶
Allows the contract owner to set the fee period duration.
Details
Signature
setFeePeriodDuration(uint _feePeriodDuration) external
Modifiers
Preconditions
_feePeriodDuration
must be no less thanMIN_FEE_PERIOD_DURATION
._feePeriodDuration
must be no greater thanMAX_FEE_PERIOD_DURATION
.
setFeePoolState
¶
Allows the contract owner to set the feePoolState
contract address.
Details
Signature
setFeePoolState(FeePoolState, _feePoolState) external
Modifiers
setRewardsAuthority
¶
Allows the contract owner to set the rewards authority.
Details
Signature
setRewardsAuthority(address _rewardsAuthority) external
Modifiers
setOikos
¶
Allows the contract owner to set the Oikos
contract address.
Details
Signature
setOikos(Synthetix _oikos) external
Modifiers
Preconditions
_oikos
must not be the zero address.
setTargetThreshold
¶
Allows the contract owner to set the collateralisation ratio target threshold.
The function requires its input as an integral percentage point value, rather than as a fractional number. So in order to set TARGET_THRESHOLD
to 0.05, provide the argument 5
. There is no way of setting a threshold between whole number percentages.
Details
Signature
setTargetThreshold(uint _percent) external
Modifiers
Preconditions
_percent
must not be negative.
Restricted Functions¶
appendAccountIssuanceRecord
¶
Records that an account issued or burnt synths in the fee pool state.
This function merely emits an event and passes through to FeePoolState.appendAccountIssuanceRecord
and is itself only invoked by Oikos._appendAccountIssuanceRecord
.
The debtRatio
argument is a 27-decimal fixed point number.
Details
Signature
appendAccountIssuanceRecord(address account, uint debtRatio, uint debtEntryIndex) external
Modifiers
Emits
recordFeePaid
¶
Allows the Oikos._internalExchange
function to record that a fee was paid whenever an exchange between Synth flavours occurs.
Adds the value in oUSD to the current fee period's pool of fees to be distributed.
setRewardsToDistribute
¶
Adds a quantity of OKS to the current fee period's total of rewards to be distributed.
Details
Signature
setRewardsToDistribute(uint amount) external
Preconditions
- Either
msg.sender
ormessageSender
must be the rewards authority address.
Internal Functions¶
_claimFees
¶
Claims fees and rewards owed to the specified address.
The account's collateralisation ratio must be less than the issuance ratio, plus the target threshold, as specified by the feesClaimable
function. The quantity of fees and rewards owed is computed by feesAvailable
.
Upon invocation, this function updates the account's last fee withdrawal time, and removes the claimed fees and rewards from the pool.
Fees are paid into the claiming address in the specified currency, while the rewards are escrowed on behalf of the claiming address in the RewardEscrow
contract for one year.
The return value is always true if the transaction was not reverted.
Details
Signature
_claimFees(address claimingAddress) internal returns (bool)
Preconditions
- The user's collateralisation ratio must be below the threshold, as per
feesClaimable
. - The user must have a positive value of fees or rewards available to claim.
Emits
FeesClaimed(claimingAddress, feesPaid, rewardsPaid)
(feesPaid
is denominated in oUSD,rewardsPaid
in OKS)
_effectiveDebtRatioForPeriod
¶
Given entry and exit indices into the debt ledger, and a percentage of total debt ownership at the entry index, this function computes the adjusted ownership percentage at the exit index. This percentage changes due to fluctuations in Synth prices and total supply.
If \Delta_i is the value of the i^{th} entry in the debt ledger and \omega is the provided debt ownership percentage, then the result of this function is:
See Oikos._addToDebtRegister
for details of the debt ownership percentage adjustment.
Details
Signature
_effectiveDebtRatioForPeriod(uint closingDebtIndex, uint ownershipPercentage, uint debtEntryIndex) internal view returns (uint)
_feesAndRewardsFromPeriod
¶
Computes the fees (in oUSD) and rewards (in OKS) owed at the end of a recent fee period given an entry index and the percentage of total system debt owned.
period
is an index into therecentFeePeriods
array, thus 0 corresponds with the current period.debtEntryIndex
should be an index into the debt ledger which was added before the close of the specified fee period.ownershipPercentage
should be the percentage of the account's debt ownership at thatdebtEntryIndex
. This is a 27-decimal fixed point number.
Details
Signature
_feesAndRewardsFromPeriod(uint period, uint ownershipPercentage, uint debtEntryIndex) internal returns (uint, uint)
_payFees
¶
Pays a quantity of fees in oUSD to a claiming address.
The quantity is burnt from the fee pool, and and then issued into the destination address.
Details
Signature
_payFees(address account, uint oUSDAmount) internal
Modifiers
Preconditions
account
can't be the fee address.account
can't be 0.account
can't be the FeePool contract itself.account
can't be the fee pool's proxy.account
can't be the Oikos contract.
_payRewards
¶
Pays a quantity of rewards to a specified address, escrowing it for one year with RewardEscrow.appendVestingEntry
.
Details
Signature
_payRewards(address account, uint snxAmount) internal
Modifiers
Preconditions
account
can't be the fee address.account
can't be 0.account
can't be the FeePool contract itself.account
can't be the fee pool's proxy.account
can't be the Oikos contract.
_recordFeePayment
¶
Claims a quantity of fees from the recent fee periods.
Fees are deducted from each period's unclaimed fees in turn from the oldest to the most recent closed period as each is exhausted until either the entire quantity has been met, or the current fee period is reached.
As fees are not paid out from the current period, if there is any quantity left to be paid after all closed periods have been exhausted, it is simply ignored. Hence any losses due to rounding errors come out of the claim of the last person to claim. The function returns the quantity of fees actually claimed, which may be less than oUSDAmount
in this case.
This is only called in _claimFees
.
In pseudo-code:
remaining = oUSDAmount # The quantity to pay out.
paid = 0 # The quantity actually paid.
# Pay out fees from recent periods, from oldest to newest as they are exhausted.
# Don't traverse the current fee period.
for each closed period in reversed(recentFeePeriods):
unclaimedFees = period.feesToDistribute - period.feesClaimed
# Skip to the next period if this one is exhausted.
if unclaimedFees == 0:
continue
# Don't pay out too much.
payable = min(unclaimedFees, remaining)
paid += payable
period.feesClaimed += payable
remaining -= payable
return paid
Details
Signature
_recordFeePayment(uint oUSDAmount) internal returns (uint)
:
_recordRewardPayment
¶
Claims a quantity of OKS rewards from the recent fee periods. This is only called in _claimFees
.
Its logic is identical to _recordFeePayment
, except that the relevant quantities are in OKS
, and are claimed from rewardsClaimed
.
Details
Signature
_recordRewardPayment(uint snxAmount) internal returns (uint)
:
_setLastFeeWithdrawal
¶
Stores into FeePoolEternalStorage the id of the fee period during which this address last withdrew fees.
Details
Signature
_setLastFeeWithdrawal(address _claimingAddress, uint _feePeriodID) internal
Modifiers¶
notFeeAddress
¶
Reverts the transaction if account
is the fee address.
Signature: notFeeAddress(address account)
onlyOikos
¶
Reverts the transaction if msg.sender
is not the oikos
address.
Events¶
ExchangeFeeUpdated
¶
Records that the fee for exchanging between Synths was updated.
This event is emitted from the FeePool's proxy with the emitExchangeFeeUpdated
function.
Signature: ExchangeFeeUpdated(uint newFeeRate)
FeesClaimed
¶
Records that an account claimed the fees and rewards owed to them.
This event is emitted from the FeePool's proxy with the emitFeesClaimed
function.
Signature: FeesClaimed(address account, uint oUSDAmount, uint snxRewards)
FeePeriodDurationUpdated
¶
Records that the duration of a single fee period was updated.
This event is emitted from the FeePool's proxy with the emitFeePeriodDurationUpdated
function.
Signature: FeePeriodDurationUpdated(uint newFeePeriodDuration)
IssuanceDebtRatioEntry
¶
Records that a new account issuance record was appended to the account's issuance ledger in FeePoolState
.
This event is emitted from the FeePool's proxy with the emitIssuanceDebtRatioEntry
function.
Signature: IssuanceDebtRatioEntry(address indexed account, uint debtRatio, uint debtEntryIndex, uint feePeriodStartingDebtIndex)