SIP-2: Remove Fee Penalty Tiers


Simple Summary

This SIP proposes to remove the current fee penalty tiers and instead to block fee claims if the user falls below the target c ratio by a specified percentage.


The fee tiers were implemented to encourage SNX holders to return their wallets to the target C ratio, in practice at the current yield no user is willingly incurring any level of fee penalty, so the penalties past 25% are unnecessary. Removing the tiers and blocking fee claims if the ratio falls below a configurable threshold will be simpler and more user friendly as a fee claim will now revert if the ratio changes while the transaction is confirming. This has happened on several occasions already and is neccesitating users paying higher gas fees to ensure fast confirmation times to avoid the risk of a penalty.


Reducing the complexity of the fee claims process and lowering the required gas for claims transactions will be a net positive for users. The fee tiers were an attempt to implement the fee penalty curve as specified in the original white paper, but empirical evidence suggest this may not have had the intended effect on user behaviour. Users are highly avoidant of fee penalties and so any non-zero fee penalty is likely to result in complete avoidance of claims until the penalty is removed. This change implements this observed behaviour into the system to reduce the risk of lost fees due to long confirmation times and other issues.



     * @notice Check if a particular address is able to claim fees right now
     * @param account The address you want to query for
    function feesClaimable(address account)
        returns (bool)
        // Penalty is calculated from ratio % above the target ratio (issuanceRatio).
        //  0  <  10%:   0% reduction in fees
        // 10% > above:  100% reduction in fees
        uint ratio = synthetix.collateralisationRatio(account);
        uint targetRatio = synthetix.synthetixState().issuanceRatio();

        // no penalty if collateral ratio below target ratio
        if (ratio < targetRatio) {
            return true;

        // Calculate the threshold for collateral ratio before penalty applies
        uint ratio_threshold = targetRatio.multiplyDecimal(SafeDecimalMath.unit().add(PENALTY_THRESHOLD));

        // Collateral ratio above threshold attracts max penalty
        if (ratio > ratio_threshold) {
            return false;

        return true;

And reverting the transaction if the currentPenalty is larger than 0 (Minters will have to fix their C-ratio to be above the penalty threshold to claim fees)

        returns (bool)
        require(feesClaimable(claimingAddress), "C-Ratio below penalty threshold");

        uint availableFees;
        uint availableRewards;
        (availableFees, availableRewards) = feesAvailable(claimingAddress, "XDR");

        require(availableFees > 0 || availableRewards > 0, "No fees or rewards available for period, or fees already claimed");

        _setLastFeeWithdrawal(claimingAddress, recentFeePeriods[1].feePeriodId);

        if (availableFees > 0) {
            // Record the fee payment in our recentFeePeriods
            uint feesPaid = _recordFeePayment(availableFees);

            // Send them their fees
            _payFees(claimingAddress, feesPaid, currencyKey);

            emitFeesClaimed(claimingAddress, feesPaid);

        if (availableRewards > 0) {
            // Record the reward payment in our recentFeePeriods
            uint rewardPaid = _recordRewardPayment(availableRewards);

            // Send them their rewards
            _payRewards(claimingAddress, rewardPaid);

            emitRewardsClaimed(claimingAddress, rewardPaid);

        return true;


Implementing a penalty threshold allows for the Collateralisation ratio to fluctuate between a certain percentage below the target issuance Ratio without the transaction reverting.

If the collateralisation ratio for the minter does fall below the threshold, then it can be fixed by burning sUSD debt before attempting to claim fees again.

Test Cases

Test cases for an implementation are mandatory for SIPs but can be included with the implementation.


The implementations must be completed before any SIP is given status "Implemented", but it need not be completed before the SIP is "Approved". While there is merit to the approach of reaching consensus on the specification and rationale before writing code, the principle of "rough consensus and running code" is still useful when it comes to resolving many discussions of API details.

Copyright and related rights waived via CC0.