pragma solidity ^0.5.16; // Inheritance import "./Owned.sol"; import "./MixinSystemSettings.sol"; import "./interfaces/ISystemSettings.sol"; import "./SystemSettingsLib.sol"; // https://docs.synthetix.io/contracts/source/contracts/systemsettings contract SystemSettings is Owned, MixinSystemSettings, ISystemSettings { // SystemSettingsLib is a way to split out the setters to reduce contract size using SystemSettingsLib for IFlexibleStorage; constructor(address _owner, address _resolver) public Owned(_owner) MixinSystemSettings(_resolver) { // SETTING_CONTRACT_NAME is defined for the getters in MixinSystemSettings and // SystemSettingsLib.contractName() is a view into SystemSettingsLib of the contract name // that's used by the setters. They have to be equal. require(SETTING_CONTRACT_NAME == SystemSettingsLib.contractName(), "read and write keys not equal"); } // ========== VIEWS ========== // backwards compatibility to having CONTRACT_NAME public constant // solhint-disable-next-line func-name-mixedcase function CONTRACT_NAME() external view returns (bytes32) { return SystemSettingsLib.contractName(); } // SIP-37 Fee Reclamation // The number of seconds after an exchange is executed that must be waited // before settlement. function waitingPeriodSecs() external view returns (uint) { return getWaitingPeriodSecs(); } // SIP-65 Decentralized Circuit Breaker // The factor amount expressed in decimal format // E.g. 3e18 = factor 3, meaning movement up to 3x and above or down to 1/3x and below function priceDeviationThresholdFactor() external view returns (uint) { return getPriceDeviationThresholdFactor(); } // The raio of collateral // Expressed in 18 decimals. So 800% cratio is 100/800 = 0.125 (0.125e18) function issuanceRatio() external view returns (uint) { return getIssuanceRatio(); } // How long a fee period lasts at a minimum. It is required for // anyone to roll over the periods, so they are not guaranteed // to roll over at exactly this duration, but the contract enforces // that they cannot roll over any quicker than this duration. function feePeriodDuration() external view returns (uint) { return getFeePeriodDuration(); } // Users are unable to claim fees if their collateralisation ratio drifts out of target threshold function targetThreshold() external view returns (uint) { return getTargetThreshold(); } // SIP-15 Liquidations // liquidation time delay after address flagged (seconds) function liquidationDelay() external view returns (uint) { return getLiquidationDelay(); } // SIP-15 Liquidations // issuance ratio when account can be flagged for liquidation (with 18 decimals), e.g 0.5 issuance ratio // when flag means 1/0.5 = 200% cratio function liquidationRatio() external view returns (uint) { return getLiquidationRatio(); } // SIP-97 Liquidations // penalty taken away from target of Collateral liquidation (with 18 decimals). E.g. 10% is 0.1e18 function liquidationPenalty() external view returns (uint) { return getLiquidationPenalty(); } // SIP-251 Differentiate Liquidation Penalties // penalty taken away from target of SNX liquidation (with 18 decimals). E.g. 30% is 0.3e18 function snxLiquidationPenalty() external view returns (uint) { return getSnxLiquidationPenalty(); } /* ========== SIP-148: Upgrade Liquidation Mechanism ========== */ /// @notice Get the escrow duration for liquidation rewards /// @return The escrow duration for liquidation rewards function liquidationEscrowDuration() external view returns (uint) { return getLiquidationEscrowDuration(); } /// @notice Get the penalty for self liquidation /// @return The self liquidation penalty function selfLiquidationPenalty() external view returns (uint) { return getSelfLiquidationPenalty(); } /// @notice Get the reward for flagging an account for liquidation /// @return The reward for flagging an account function flagReward() external view returns (uint) { return getFlagReward(); } /// @notice Get the reward for liquidating an account /// @return The reward for performing a forced liquidation function liquidateReward() external view returns (uint) { return getLiquidateReward(); } /* ========== End SIP-148 ========== */ // How long will the ExchangeRates contract assume the rate of any asset is correct function rateStalePeriod() external view returns (uint) { return getRateStalePeriod(); } /* ========== Exchange Related Fees ========== */ function exchangeFeeRate(bytes32 currencyKey) external view returns (uint) { return getExchangeFeeRate(currencyKey); } // SIP-184 Dynamic Fee /// @notice Get the dynamic fee threshold /// @return The dynamic fee threshold function exchangeDynamicFeeThreshold() external view returns (uint) { return getExchangeDynamicFeeConfig().threshold; } /// @notice Get the dynamic fee weight decay per round /// @return The dynamic fee weight decay per round function exchangeDynamicFeeWeightDecay() external view returns (uint) { return getExchangeDynamicFeeConfig().weightDecay; } /// @notice Get the dynamic fee total rounds for calculation /// @return The dynamic fee total rounds for calculation function exchangeDynamicFeeRounds() external view returns (uint) { return getExchangeDynamicFeeConfig().rounds; } /// @notice Get the max dynamic fee /// @return The max dynamic fee function exchangeMaxDynamicFee() external view returns (uint) { return getExchangeDynamicFeeConfig().maxFee; } /* ========== End Exchange Related Fees ========== */ function minimumStakeTime() external view returns (uint) { return getMinimumStakeTime(); } function debtSnapshotStaleTime() external view returns (uint) { return getDebtSnapshotStaleTime(); } function aggregatorWarningFlags() external view returns (address) { return getAggregatorWarningFlags(); } // SIP-63 Trading incentives // determines if Exchanger records fee entries in TradingRewards function tradingRewardsEnabled() external view returns (bool) { return getTradingRewardsEnabled(); } function crossDomainMessageGasLimit(CrossDomainMessageGasLimits gasLimitType) external view returns (uint) { return getCrossDomainMessageGasLimit(gasLimitType); } // SIP 112: ETH Wrappr // The maximum amount of ETH held by the EtherWrapper. function etherWrapperMaxETH() external view returns (uint) { return getEtherWrapperMaxETH(); } // SIP 112: ETH Wrappr // The fee for depositing ETH into the EtherWrapper. function etherWrapperMintFeeRate() external view returns (uint) { return getEtherWrapperMintFeeRate(); } // SIP 112: ETH Wrappr // The fee for burning sETH and releasing ETH from the EtherWrapper. function etherWrapperBurnFeeRate() external view returns (uint) { return getEtherWrapperBurnFeeRate(); } // SIP 182: Wrapper Factory // The maximum amount of token held by the Wrapper. function wrapperMaxTokenAmount(address wrapper) external view returns (uint) { return getWrapperMaxTokenAmount(wrapper); } // SIP 182: Wrapper Factory // The fee for depositing token into the Wrapper. function wrapperMintFeeRate(address wrapper) external view returns (int) { return getWrapperMintFeeRate(wrapper); } // SIP 182: Wrapper Factory // The fee for burning synth and releasing token from the Wrapper. function wrapperBurnFeeRate(address wrapper) external view returns (int) { return getWrapperBurnFeeRate(wrapper); } function interactionDelay(address collateral) external view returns (uint) { return getInteractionDelay(collateral); } function collapseFeeRate(address collateral) external view returns (uint) { return getCollapseFeeRate(collateral); } // SIP-120 Atomic exchanges // max allowed volume per block for atomic exchanges function atomicMaxVolumePerBlock() external view returns (uint) { return getAtomicMaxVolumePerBlock(); } // SIP-120 Atomic exchanges // time window (in seconds) for TWAP prices when considered for atomic exchanges function atomicTwapWindow() external view returns (uint) { return getAtomicTwapWindow(); } // SIP-120 Atomic exchanges // equivalent asset to use for a synth when considering external prices for atomic exchanges function atomicEquivalentForDexPricing(bytes32 currencyKey) external view returns (address) { return getAtomicEquivalentForDexPricing(currencyKey); } // SIP-120 Atomic exchanges // fee rate override for atomic exchanges into a synth function atomicExchangeFeeRate(bytes32 currencyKey) external view returns (uint) { return getAtomicExchangeFeeRate(currencyKey); } // SIP-120 Atomic exchanges // consideration window for determining synth volatility function atomicVolatilityConsiderationWindow(bytes32 currencyKey) external view returns (uint) { return getAtomicVolatilityConsiderationWindow(currencyKey); } // SIP-120 Atomic exchanges // update threshold for determining synth volatility function atomicVolatilityUpdateThreshold(bytes32 currencyKey) external view returns (uint) { return getAtomicVolatilityUpdateThreshold(currencyKey); } // SIP-198: Atomic Exchange At Pure Chainlink Price // Whether to use the pure Chainlink price for a given currency key function pureChainlinkPriceForAtomicSwapsEnabled(bytes32 currencyKey) external view returns (bool) { return getPureChainlinkPriceForAtomicSwapsEnabled(currencyKey); } // SIP-229 Atomic exchanges // enable/disable sending of synths cross chain function crossChainSynthTransferEnabled(bytes32 currencyKey) external view returns (uint) { return getCrossChainSynthTransferEnabled(currencyKey); } // ========== RESTRICTED ========== function setCrossDomainMessageGasLimit(CrossDomainMessageGasLimits _gasLimitType, uint _crossDomainMessageGasLimit) external onlyOwner { flexibleStorage().setCrossDomainMessageGasLimit(_getGasLimitSetting(_gasLimitType), _crossDomainMessageGasLimit); emit CrossDomainMessageGasLimitChanged(_gasLimitType, _crossDomainMessageGasLimit); } function setIssuanceRatio(uint ratio) external onlyOwner { flexibleStorage().setIssuanceRatio(SETTING_ISSUANCE_RATIO, ratio); emit IssuanceRatioUpdated(ratio); } function setTradingRewardsEnabled(bool _tradingRewardsEnabled) external onlyOwner { flexibleStorage().setTradingRewardsEnabled(SETTING_TRADING_REWARDS_ENABLED, _tradingRewardsEnabled); emit TradingRewardsEnabled(_tradingRewardsEnabled); } function setWaitingPeriodSecs(uint _waitingPeriodSecs) external onlyOwner { flexibleStorage().setWaitingPeriodSecs(SETTING_WAITING_PERIOD_SECS, _waitingPeriodSecs); emit WaitingPeriodSecsUpdated(_waitingPeriodSecs); } function setPriceDeviationThresholdFactor(uint _priceDeviationThresholdFactor) external onlyOwner { flexibleStorage().setPriceDeviationThresholdFactor( SETTING_PRICE_DEVIATION_THRESHOLD_FACTOR, _priceDeviationThresholdFactor ); emit PriceDeviationThresholdUpdated(_priceDeviationThresholdFactor); } function setFeePeriodDuration(uint _feePeriodDuration) external onlyOwner { flexibleStorage().setFeePeriodDuration(SETTING_FEE_PERIOD_DURATION, _feePeriodDuration); emit FeePeriodDurationUpdated(_feePeriodDuration); } function setTargetThreshold(uint percent) external onlyOwner { uint threshold = flexibleStorage().setTargetThreshold(SETTING_TARGET_THRESHOLD, percent); emit TargetThresholdUpdated(threshold); } function setLiquidationDelay(uint time) external onlyOwner { flexibleStorage().setLiquidationDelay(SETTING_LIQUIDATION_DELAY, time); emit LiquidationDelayUpdated(time); } // The collateral / issuance ratio ( debt / collateral ) is higher when there is less collateral backing their debt // Upper bound liquidationRatio is 1 + penalty (100% + 10% = 110%) to allow collateral value to cover debt and liquidation penalty function setLiquidationRatio(uint _liquidationRatio) external onlyOwner { flexibleStorage().setLiquidationRatio( SETTING_LIQUIDATION_RATIO, _liquidationRatio, getSnxLiquidationPenalty(), getIssuanceRatio() ); emit LiquidationRatioUpdated(_liquidationRatio); } function setLiquidationEscrowDuration(uint duration) external onlyOwner { flexibleStorage().setUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_ESCROW_DURATION, duration); emit LiquidationEscrowDurationUpdated(duration); } function setSnxLiquidationPenalty(uint penalty) external onlyOwner { flexibleStorage().setSnxLiquidationPenalty(SETTING_SNX_LIQUIDATION_PENALTY, penalty); emit SnxLiquidationPenaltyUpdated(penalty); } function setLiquidationPenalty(uint penalty) external onlyOwner { flexibleStorage().setLiquidationPenalty(SETTING_LIQUIDATION_PENALTY, penalty); emit LiquidationPenaltyUpdated(penalty); } function setSelfLiquidationPenalty(uint penalty) external onlyOwner { flexibleStorage().setSelfLiquidationPenalty(SETTING_SELF_LIQUIDATION_PENALTY, penalty); emit SelfLiquidationPenaltyUpdated(penalty); } function setFlagReward(uint reward) external onlyOwner { flexibleStorage().setUIntValue(SETTING_CONTRACT_NAME, SETTING_FLAG_REWARD, reward); emit FlagRewardUpdated(reward); } function setLiquidateReward(uint reward) external onlyOwner { flexibleStorage().setUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATE_REWARD, reward); emit LiquidateRewardUpdated(reward); } function setRateStalePeriod(uint period) external onlyOwner { flexibleStorage().setRateStalePeriod(SETTING_RATE_STALE_PERIOD, period); emit RateStalePeriodUpdated(period); } /* ========== Exchange Fees Related ========== */ function setExchangeFeeRateForSynths(bytes32[] calldata synthKeys, uint256[] calldata exchangeFeeRates) external onlyOwner { flexibleStorage().setExchangeFeeRateForSynths(SETTING_EXCHANGE_FEE_RATE, synthKeys, exchangeFeeRates); for (uint i = 0; i < synthKeys.length; i++) { emit ExchangeFeeUpdated(synthKeys[i], exchangeFeeRates[i]); } } /// @notice Set exchange dynamic fee threshold constant in decimal ratio /// @param threshold The exchange dynamic fee threshold /// @return uint threshold constant function setExchangeDynamicFeeThreshold(uint threshold) external onlyOwner { require(threshold != 0, "Threshold cannot be 0"); flexibleStorage().setUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_DYNAMIC_FEE_THRESHOLD, threshold); emit ExchangeDynamicFeeThresholdUpdated(threshold); } /// @notice Set exchange dynamic fee weight decay constant /// @param weightDecay The exchange dynamic fee weight decay /// @return uint weight decay constant function setExchangeDynamicFeeWeightDecay(uint weightDecay) external onlyOwner { require(weightDecay != 0, "Weight decay cannot be 0"); flexibleStorage().setUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_DYNAMIC_FEE_WEIGHT_DECAY, weightDecay); emit ExchangeDynamicFeeWeightDecayUpdated(weightDecay); } /// @notice Set exchange dynamic fee last N rounds with minimum 2 rounds /// @param rounds The exchange dynamic fee last N rounds /// @return uint dynamic fee last N rounds function setExchangeDynamicFeeRounds(uint rounds) external onlyOwner { flexibleStorage().setUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_DYNAMIC_FEE_ROUNDS, rounds); emit ExchangeDynamicFeeRoundsUpdated(rounds); } /// @notice Set max exchange dynamic fee /// @param maxFee The max exchange dynamic fee /// @return uint dynamic fee last N rounds function setExchangeMaxDynamicFee(uint maxFee) external onlyOwner { flexibleStorage().setExchangeMaxDynamicFee(SETTING_EXCHANGE_MAX_DYNAMIC_FEE, maxFee); emit ExchangeMaxDynamicFeeUpdated(maxFee); } function setMinimumStakeTime(uint _seconds) external onlyOwner { flexibleStorage().setMinimumStakeTime(SETTING_MINIMUM_STAKE_TIME, _seconds); emit MinimumStakeTimeUpdated(_seconds); } function setDebtSnapshotStaleTime(uint _seconds) external onlyOwner { flexibleStorage().setDebtSnapshotStaleTime(SETTING_DEBT_SNAPSHOT_STALE_TIME, _seconds); emit DebtSnapshotStaleTimeUpdated(_seconds); } function setAggregatorWarningFlags(address _flags) external onlyOwner { flexibleStorage().setAggregatorWarningFlags(SETTING_AGGREGATOR_WARNING_FLAGS, _flags); emit AggregatorWarningFlagsUpdated(_flags); } function setEtherWrapperMaxETH(uint _maxETH) external onlyOwner { flexibleStorage().setEtherWrapperMaxETH(SETTING_ETHER_WRAPPER_MAX_ETH, _maxETH); emit EtherWrapperMaxETHUpdated(_maxETH); } function setEtherWrapperMintFeeRate(uint _rate) external onlyOwner { flexibleStorage().setEtherWrapperMintFeeRate(SETTING_ETHER_WRAPPER_MINT_FEE_RATE, _rate); emit EtherWrapperMintFeeRateUpdated(_rate); } function setEtherWrapperBurnFeeRate(uint _rate) external onlyOwner { flexibleStorage().setEtherWrapperBurnFeeRate(SETTING_ETHER_WRAPPER_BURN_FEE_RATE, _rate); emit EtherWrapperBurnFeeRateUpdated(_rate); } function setWrapperMaxTokenAmount(address _wrapper, uint _maxTokenAmount) external onlyOwner { flexibleStorage().setWrapperMaxTokenAmount(SETTING_WRAPPER_MAX_TOKEN_AMOUNT, _wrapper, _maxTokenAmount); emit WrapperMaxTokenAmountUpdated(_wrapper, _maxTokenAmount); } function setWrapperMintFeeRate(address _wrapper, int _rate) external onlyOwner { flexibleStorage().setWrapperMintFeeRate( SETTING_WRAPPER_MINT_FEE_RATE, _wrapper, _rate, getWrapperBurnFeeRate(_wrapper) ); emit WrapperMintFeeRateUpdated(_wrapper, _rate); } function setWrapperBurnFeeRate(address _wrapper, int _rate) external onlyOwner { flexibleStorage().setWrapperBurnFeeRate( SETTING_WRAPPER_BURN_FEE_RATE, _wrapper, _rate, getWrapperMintFeeRate(_wrapper) ); emit WrapperBurnFeeRateUpdated(_wrapper, _rate); } function setInteractionDelay(address _collateral, uint _interactionDelay) external onlyOwner { flexibleStorage().setInteractionDelay(SETTING_INTERACTION_DELAY, _collateral, _interactionDelay); emit InteractionDelayUpdated(_interactionDelay); } function setCollapseFeeRate(address _collateral, uint _collapseFeeRate) external onlyOwner { flexibleStorage().setCollapseFeeRate(SETTING_COLLAPSE_FEE_RATE, _collateral, _collapseFeeRate); emit CollapseFeeRateUpdated(_collapseFeeRate); } function setAtomicMaxVolumePerBlock(uint _maxVolume) external onlyOwner { flexibleStorage().setAtomicMaxVolumePerBlock(SETTING_ATOMIC_MAX_VOLUME_PER_BLOCK, _maxVolume); emit AtomicMaxVolumePerBlockUpdated(_maxVolume); } function setAtomicTwapWindow(uint _window) external onlyOwner { flexibleStorage().setAtomicTwapWindow(SETTING_ATOMIC_TWAP_WINDOW, _window); emit AtomicTwapWindowUpdated(_window); } function setAtomicEquivalentForDexPricing(bytes32 _currencyKey, address _equivalent) external onlyOwner { flexibleStorage().setAtomicEquivalentForDexPricing( SETTING_ATOMIC_EQUIVALENT_FOR_DEX_PRICING, _currencyKey, _equivalent ); emit AtomicEquivalentForDexPricingUpdated(_currencyKey, _equivalent); } function setAtomicExchangeFeeRate(bytes32 _currencyKey, uint256 _exchangeFeeRate) external onlyOwner { flexibleStorage().setAtomicExchangeFeeRate(SETTING_ATOMIC_EXCHANGE_FEE_RATE, _currencyKey, _exchangeFeeRate); emit AtomicExchangeFeeUpdated(_currencyKey, _exchangeFeeRate); } function setAtomicVolatilityConsiderationWindow(bytes32 _currencyKey, uint _window) external onlyOwner { flexibleStorage().setAtomicVolatilityConsiderationWindow( SETTING_ATOMIC_VOLATILITY_CONSIDERATION_WINDOW, _currencyKey, _window ); emit AtomicVolatilityConsiderationWindowUpdated(_currencyKey, _window); } function setAtomicVolatilityUpdateThreshold(bytes32 _currencyKey, uint _threshold) external onlyOwner { flexibleStorage().setAtomicVolatilityUpdateThreshold( SETTING_ATOMIC_VOLATILITY_UPDATE_THRESHOLD, _currencyKey, _threshold ); emit AtomicVolatilityUpdateThresholdUpdated(_currencyKey, _threshold); } function setPureChainlinkPriceForAtomicSwapsEnabled(bytes32 _currencyKey, bool _enabled) external onlyOwner { flexibleStorage().setPureChainlinkPriceForAtomicSwapsEnabled( SETTING_PURE_CHAINLINK_PRICE_FOR_ATOMIC_SWAPS_ENABLED, _currencyKey, _enabled ); emit PureChainlinkPriceForAtomicSwapsEnabledUpdated(_currencyKey, _enabled); } function setCrossChainSynthTransferEnabled(bytes32 _currencyKey, uint _value) external onlyOwner { flexibleStorage().setCrossChainSynthTransferEnabled(SETTING_CROSS_SYNTH_TRANSFER_ENABLED, _currencyKey, _value); emit CrossChainSynthTransferEnabledUpdated(_currencyKey, _value); } // ========== EVENTS ========== event CrossDomainMessageGasLimitChanged(CrossDomainMessageGasLimits gasLimitType, uint newLimit); event IssuanceRatioUpdated(uint newRatio); event TradingRewardsEnabled(bool enabled); event WaitingPeriodSecsUpdated(uint waitingPeriodSecs); event PriceDeviationThresholdUpdated(uint threshold); event FeePeriodDurationUpdated(uint newFeePeriodDuration); event TargetThresholdUpdated(uint newTargetThreshold); event LiquidationDelayUpdated(uint newDelay); event LiquidationRatioUpdated(uint newRatio); event LiquidationEscrowDurationUpdated(uint newDuration); event LiquidationPenaltyUpdated(uint newPenalty); event SnxLiquidationPenaltyUpdated(uint newPenalty); event SelfLiquidationPenaltyUpdated(uint newPenalty); event FlagRewardUpdated(uint newReward); event LiquidateRewardUpdated(uint newReward); event RateStalePeriodUpdated(uint rateStalePeriod); /* ========== Exchange Fees Related ========== */ event ExchangeFeeUpdated(bytes32 synthKey, uint newExchangeFeeRate); event ExchangeDynamicFeeThresholdUpdated(uint dynamicFeeThreshold); event ExchangeDynamicFeeWeightDecayUpdated(uint dynamicFeeWeightDecay); event ExchangeDynamicFeeRoundsUpdated(uint dynamicFeeRounds); event ExchangeMaxDynamicFeeUpdated(uint maxDynamicFee); /* ========== End Exchange Fees Related ========== */ event MinimumStakeTimeUpdated(uint minimumStakeTime); event DebtSnapshotStaleTimeUpdated(uint debtSnapshotStaleTime); event AggregatorWarningFlagsUpdated(address flags); event EtherWrapperMaxETHUpdated(uint maxETH); event EtherWrapperMintFeeRateUpdated(uint rate); event EtherWrapperBurnFeeRateUpdated(uint rate); event WrapperMaxTokenAmountUpdated(address wrapper, uint maxTokenAmount); event WrapperMintFeeRateUpdated(address wrapper, int rate); event WrapperBurnFeeRateUpdated(address wrapper, int rate); event InteractionDelayUpdated(uint interactionDelay); event CollapseFeeRateUpdated(uint collapseFeeRate); event AtomicMaxVolumePerBlockUpdated(uint newMaxVolume); event AtomicTwapWindowUpdated(uint newWindow); event AtomicEquivalentForDexPricingUpdated(bytes32 synthKey, address equivalent); event AtomicExchangeFeeUpdated(bytes32 synthKey, uint newExchangeFeeRate); event AtomicVolatilityConsiderationWindowUpdated(bytes32 synthKey, uint newVolatilityConsiderationWindow); event AtomicVolatilityUpdateThresholdUpdated(bytes32 synthKey, uint newVolatilityUpdateThreshold); event PureChainlinkPriceForAtomicSwapsEnabledUpdated(bytes32 synthKey, bool enabled); event CrossChainSynthTransferEnabledUpdated(bytes32 synthKey, uint value); }