Skip to content

FeePool

Description

Source: FeePool.sol

Architecture


Inheritance Graph

FeePool inheritance graph


FeePool architecture graph

Details
  • Proxy: The fee pool, being Proxyable, sits behind a CALL-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 the rewardsAuthority, 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


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


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 exceed FEE_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).

Details

Signature

claimFees() external returns (bool)

Modifiers


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


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


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


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.

Details

Signature

recordFeePaid(uint amount) external

Modifiers


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


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

Emits


_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:

\omega \frac{\Delta_\text{exit}}{\Delta_\text{entry}}

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 the recentFeePeriods 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 that debtEntryIndex. 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)