SIP-174: Redeem Deprecated Synths


Simple Summary

Allow synths to be removed from the protocol without the need to purge holders back to sUSD.


In order to easily remove synths from the protocol, a contract will be created that will allow holders of a synth that is deprecated to redeem them at a fixed price for sUSD.


To remove a synth from the protocol, its totalSupply must be 0, to account for the debt pool. To achieve this in the past the protocolDAO has manually purged holders back to sUSD. On top of the obvious overhead this causes, there is the greater concern that the purged holders may be contracts - such as AMM pools like Balancer, Curve, et al - and purging their synths to sUSD would cause them to potentially fail.



Allow the owner of the protocol to remove a synth with existing supply by issuing the equivalent amount of sUSD of the synth's open interest at the current exchange rate to a new contract SynthRedeemer and allowing holders to redeem back to sUSD at any time in the future their deprecated synths using the redeem rate.

When a user later invokes SynthRedeemer.redeem(IERC20) then contract will burn the synth tokens and send the user the equivalent amount of sUSD.


By connecting the SynthRedeemer contract to Issuer.removeSynth(), we can atomically ensure the debt pool is balanced by issuing the equivalent amount of sUSD to account for the debt removed from the system by the synth's supply. Moreover, when the redeemer attempts to burn, it can instruct the synth to burn via the Issuer which has the privileges to do so.

Technical Specification

interface ISynthRedeemer {
    // Rate of redemption - 0 for none
    function redemptions(address token) external view returns (uint redeemRate);

    // sUSD balance of deprecated token holder
    function balanceOf(IERC20 token, address account) external view returns (uint balanceOfInsUSD);

    // Full sUSD supply of token
    function totalSupply(IERC20 tokens) external view returns (uint totalSupplyInsUSD);

    function redeem(IERC20 token) external;

    function redeemAll(IERC20[] calldata tokens) external;

    function redeemPartial(IERC20 token, uint amountOfSynth) external;

    // Restricted to Issuer
    function deprecate(IERC20 token, uint rateToRedeem) external;

    // Events
    event SynthRedeemed(address synth, address account, uint amountOfSynth, uint amountInsUSD);

    event SynthDeprecated(address synth, uint rateToRedeem, uint totalSynthSupply, uint supplyInsUSD);

Test Cases

  • When non-owner calls Issuer.removeSynth(*) it reverts (same as the current system)
  • When owner calls Issuer.removeSynth(sUSD) it reverts (same as the current system)
  • Given the rate of sAAVE is 500 and the totalSupply is 10
    • When owner calls Issuer.removeSynth(sAAVE), Then 5000 sUSD is issued to the SynthRedeemer contract, SynthRedeemer.deprecate(ProxysAAVE) is invoked setting the redemptions rate to 500 and sAAVE is removed from synthetix.
      • Given Alice holds 4 units of sAAVE, When Alice calls SynthRedeemer.redeem(sAAVE), then she receives 2000 sUSD from the SynthRedeemer contract, and all of her sAAVE is burned.

Configurable Values (Via SCCP)


Copyright and related rights waived via CC0.