Skip to content

Commit

Permalink
Merge branch 'develop' into releases-json-doc
Browse files Browse the repository at this point in the history
  • Loading branch information
liamzebedee authored Nov 2, 2021
2 parents d7cbe66 + 94987e3 commit 25c2c61
Show file tree
Hide file tree
Showing 44 changed files with 3,600 additions and 445 deletions.
80 changes: 64 additions & 16 deletions contracts/BaseDebtCache.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import "./interfaces/ISystemStatus.sol";
import "./interfaces/IERC20.sol";
import "./interfaces/ICollateralManager.sol";
import "./interfaces/IEtherWrapper.sol";
import "./interfaces/IWrapperFactory.sol";

//
// The debt cache (SIP-91) caches the global debt and the debt of each synth in the system.
Expand All @@ -37,6 +38,7 @@ contract BaseDebtCache is Owned, MixinSystemSettings, IDebtCache {

uint internal _cachedDebt;
mapping(bytes32 => uint) internal _cachedSynthDebt;
mapping(bytes32 => uint) internal _excludedIssuedDebt;
uint internal _cacheTimestamp;
bool internal _cacheInvalid = true;

Expand All @@ -53,20 +55,22 @@ contract BaseDebtCache is Owned, MixinSystemSettings, IDebtCache {
bytes32 private constant CONTRACT_SYSTEMSTATUS = "SystemStatus";
bytes32 private constant CONTRACT_COLLATERALMANAGER = "CollateralManager";
bytes32 private constant CONTRACT_ETHER_WRAPPER = "EtherWrapper";
bytes32 private constant CONTRACT_WRAPPER_FACTORY = "WrapperFactory";

constructor(address _owner, address _resolver) public Owned(_owner) MixinSystemSettings(_resolver) {}

/* ========== VIEWS ========== */

function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
bytes32[] memory existingAddresses = MixinSystemSettings.resolverAddressesRequired();
bytes32[] memory newAddresses = new bytes32[](6);
bytes32[] memory newAddresses = new bytes32[](7);
newAddresses[0] = CONTRACT_ISSUER;
newAddresses[1] = CONTRACT_EXCHANGER;
newAddresses[2] = CONTRACT_EXRATES;
newAddresses[3] = CONTRACT_SYSTEMSTATUS;
newAddresses[4] = CONTRACT_COLLATERALMANAGER;
newAddresses[5] = CONTRACT_ETHER_WRAPPER;
newAddresses[5] = CONTRACT_WRAPPER_FACTORY;
newAddresses[6] = CONTRACT_ETHER_WRAPPER;
addresses = combineArrays(existingAddresses, newAddresses);
}

Expand Down Expand Up @@ -94,6 +98,10 @@ contract BaseDebtCache is Owned, MixinSystemSettings, IDebtCache {
return IEtherWrapper(requireAndGetAddress(CONTRACT_ETHER_WRAPPER));
}

function wrapperFactory() internal view returns (IWrapperFactory) {
return IWrapperFactory(requireAndGetAddress(CONTRACT_WRAPPER_FACTORY));
}

function debtSnapshotStaleTime() external view returns (uint) {
return getDebtSnapshotStaleTime();
}
Expand Down Expand Up @@ -125,7 +133,6 @@ contract BaseDebtCache is Owned, MixinSystemSettings, IDebtCache {
return _cacheStale(_cacheTimestamp);
}

// Returns the USD-denominated supply of each synth in `currencyKeys`, according to `rates`.
function _issuedSynthValues(bytes32[] memory currencyKeys, uint[] memory rates)
internal
view
Expand Down Expand Up @@ -156,11 +163,11 @@ contract BaseDebtCache is Owned, MixinSystemSettings, IDebtCache {
{
(uint[] memory rates, bool isInvalid) = exchangeRates().ratesAndInvalidForCurrencies(currencyKeys);
uint[] memory values = _issuedSynthValues(currencyKeys, rates);
(uint excludedDebt, bool isAnyNonSnxDebtRateInvalid) = _totalNonSnxBackedDebt();
return (values, excludedDebt, isInvalid || isAnyNonSnxDebtRateInvalid);
(uint excludedDebt, bool isAnyNonSnxDebtRateInvalid) = _totalNonSnxBackedDebt(currencyKeys, rates, isInvalid);

return (values, excludedDebt, isAnyNonSnxDebtRateInvalid);
}

// Returns the USD-denominated supply of each synth in `currencyKeys`, using current exchange rates.
function currentSynthDebts(bytes32[] calldata currencyKeys)
external
view
Expand All @@ -186,24 +193,50 @@ contract BaseDebtCache is Owned, MixinSystemSettings, IDebtCache {
return _cachedSynthDebts(currencyKeys);
}

function _totalNonSnxBackedDebt() internal view returns (uint excludedDebt, bool isInvalid) {
function _excludedIssuedDebts(bytes32[] memory currencyKeys) internal view returns (uint[] memory) {
uint numKeys = currencyKeys.length;
uint[] memory debts = new uint[](numKeys);
for (uint i = 0; i < numKeys; i++) {
debts[i] = _excludedIssuedDebt[currencyKeys[i]];
}
return debts;
}

function excludedIssuedDebts(bytes32[] calldata currencyKeys) external view returns (uint[] memory excludedDebts) {
return _excludedIssuedDebts(currencyKeys);
}

// Returns the total sUSD debt backed by non-SNX collateral.
function totalNonSnxBackedDebt() external view returns (uint excludedDebt, bool isInvalid) {
bytes32[] memory currencyKeys = issuer().availableCurrencyKeys();
(uint[] memory rates, bool ratesAreInvalid) = exchangeRates().ratesAndInvalidForCurrencies(currencyKeys);

return _totalNonSnxBackedDebt(currencyKeys, rates, ratesAreInvalid);
}

function _totalNonSnxBackedDebt(
bytes32[] memory currencyKeys,
uint[] memory rates,
bool ratesAreInvalid
) internal view returns (uint excludedDebt, bool isInvalid) {
// Calculate excluded debt.
// 1. MultiCollateral long debt + short debt.
(uint longValue, bool anyTotalLongRateIsInvalid) = collateralManager().totalLong();
(uint shortValue, bool anyTotalShortRateIsInvalid) = collateralManager().totalShort();
isInvalid = anyTotalLongRateIsInvalid || anyTotalShortRateIsInvalid;
isInvalid = ratesAreInvalid || anyTotalLongRateIsInvalid || anyTotalShortRateIsInvalid;
excludedDebt = longValue.add(shortValue);

// 2. EtherWrapper.
// Subtract sETH and sUSD issued by EtherWrapper.
excludedDebt = excludedDebt.add(etherWrapper().totalIssuedSynths());

return (excludedDebt, isInvalid);
}
// 3. WrapperFactory.
// Get the debt issued by the Wrappers.
for (uint i = 0; i < currencyKeys.length; i++) {
excludedDebt = excludedDebt.add(_excludedIssuedDebt[currencyKeys[i]].multiplyDecimalRound(rates[i]));
}

// Returns the total sUSD debt backed by non-SNX collateral.
function totalNonSnxBackedDebt() external view returns (uint excludedDebt, bool isInvalid) {
return _totalNonSnxBackedDebt();
return (excludedDebt, isInvalid);
}

function _currentDebt() internal view returns (uint debt, bool anyRateIsInvalid) {
Expand All @@ -212,7 +245,7 @@ contract BaseDebtCache is Owned, MixinSystemSettings, IDebtCache {

// Sum all issued synth values based on their supply.
uint[] memory values = _issuedSynthValues(currencyKeys, rates);
(uint excludedDebt, bool isAnyNonSnxDebtRateInvalid) = _totalNonSnxBackedDebt();
(uint excludedDebt, bool isAnyNonSnxDebtRateInvalid) = _totalNonSnxBackedDebt(currencyKeys, rates, isInvalid);

uint numValues = values.length;
uint total;
Expand All @@ -221,10 +254,9 @@ contract BaseDebtCache is Owned, MixinSystemSettings, IDebtCache {
}
total = total < excludedDebt ? 0 : total.sub(excludedDebt);

return (total, isInvalid || isAnyNonSnxDebtRateInvalid);
return (total, isAnyNonSnxDebtRateInvalid);
}

// Returns the current debt of the system, excluding non-SNX backed debt (eg. EtherWrapper).
function currentDebt() external view returns (uint debt, bool anyRateIsInvalid) {
return _currentDebt();
}
Expand Down Expand Up @@ -260,6 +292,8 @@ contract BaseDebtCache is Owned, MixinSystemSettings, IDebtCache {

function takeDebtSnapshot() external {}

function recordExcludedDebtChange(bytes32 currencyKey, int256 delta) external {}

/* ========== MODIFIERS ========== */

function _requireSystemActiveIfNotOwner() internal view {
Expand Down Expand Up @@ -290,4 +324,18 @@ contract BaseDebtCache is Owned, MixinSystemSettings, IDebtCache {
_onlyIssuerOrExchanger();
_;
}

function _onlyDebtIssuer() internal view {
bool isWrapper = wrapperFactory().isWrapper(msg.sender);

// owner included for debugging and fixing in emergency situation
bool isOwner = msg.sender == owner;

require(isOwner || isWrapper, "Only debt issuers may call this");
}

modifier onlyDebtIssuer() {
_onlyDebtIssuer();
_;
}
}
8 changes: 8 additions & 0 deletions contracts/DebtCache.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ contract DebtCache is BaseDebtCache {
_updateDebtCacheValidity(currentlyInvalid);
}

function recordExcludedDebtChange(bytes32 currencyKey, int256 delta) external onlyDebtIssuer {
int256 newExcludedDebt = int256(_excludedIssuedDebt[currencyKey]) + delta;

require(newExcludedDebt >= 0, "Excluded debt cannot become negative");

_excludedIssuedDebt[currencyKey] = uint(newExcludedDebt);
}

function updateCachedsUSDDebt(int amount) external onlyIssuer {
uint delta = SafeDecimalMath.abs(amount);
if (amount > 0) {
Expand Down
15 changes: 12 additions & 3 deletions contracts/FeePool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import "./interfaces/IDelegateApprovals.sol";
import "./interfaces/IRewardsDistribution.sol";
import "./interfaces/ICollateralManager.sol";
import "./interfaces/IEtherWrapper.sol";
import "./interfaces/IWrapperFactory.sol";

// https://docs.synthetix.io/contracts/source/contracts/feepool
contract FeePool is Owned, Proxyable, LimitedSetup, MixinSystemSettings, IFeePool {
Expand Down Expand Up @@ -75,6 +76,7 @@ contract FeePool is Owned, Proxyable, LimitedSetup, MixinSystemSettings, IFeePoo
bytes32 private constant CONTRACT_COLLATERALMANAGER = "CollateralManager";
bytes32 private constant CONTRACT_REWARDSDISTRIBUTION = "RewardsDistribution";
bytes32 private constant CONTRACT_ETHER_WRAPPER = "EtherWrapper";
bytes32 private constant CONTRACT_WRAPPER_FACTORY = "WrapperFactory";

/* ========== ETERNAL STORAGE CONSTANTS ========== */

Expand All @@ -93,7 +95,7 @@ contract FeePool is Owned, Proxyable, LimitedSetup, MixinSystemSettings, IFeePoo
/* ========== VIEWS ========== */
function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
bytes32[] memory existingAddresses = MixinSystemSettings.resolverAddressesRequired();
bytes32[] memory newAddresses = new bytes32[](12);
bytes32[] memory newAddresses = new bytes32[](13);
newAddresses[0] = CONTRACT_SYSTEMSTATUS;
newAddresses[1] = CONTRACT_SYNTHETIX;
newAddresses[2] = CONTRACT_FEEPOOLSTATE;
Expand All @@ -105,7 +107,8 @@ contract FeePool is Owned, Proxyable, LimitedSetup, MixinSystemSettings, IFeePoo
newAddresses[8] = CONTRACT_DELEGATEAPPROVALS;
newAddresses[9] = CONTRACT_REWARDSDISTRIBUTION;
newAddresses[10] = CONTRACT_COLLATERALMANAGER;
newAddresses[11] = CONTRACT_ETHER_WRAPPER;
newAddresses[11] = CONTRACT_WRAPPER_FACTORY;
newAddresses[12] = CONTRACT_ETHER_WRAPPER;
addresses = combineArrays(existingAddresses, newAddresses);
}

Expand Down Expand Up @@ -157,6 +160,10 @@ contract FeePool is Owned, Proxyable, LimitedSetup, MixinSystemSettings, IFeePoo
return IEtherWrapper(requireAndGetAddress(CONTRACT_ETHER_WRAPPER));
}

function wrapperFactory() internal view returns (IWrapperFactory) {
return IWrapperFactory(requireAndGetAddress(CONTRACT_WRAPPER_FACTORY));
}

function issuanceRatio() external view returns (uint) {
return getIssuanceRatio();
}
Expand Down Expand Up @@ -250,6 +257,7 @@ contract FeePool is Owned, Proxyable, LimitedSetup, MixinSystemSettings, IFeePoo
require(_recentFeePeriodsStorage(0).startTime <= (now - getFeePeriodDuration()), "Too early to close fee period");

etherWrapper().distributeFees();
wrapperFactory().distributeFees();

// Note: when FEE_PERIOD_LENGTH = 2, periodClosing is the current period & periodToRollover is the last open claimable period
FeePeriod storage periodClosing = _recentFeePeriodsStorage(FEE_PERIOD_LENGTH - 2);
Expand Down Expand Up @@ -725,8 +733,9 @@ contract FeePool is Owned, Proxyable, LimitedSetup, MixinSystemSettings, IFeePoo
bool isSynth = issuer().synthsByAddress(msg.sender) != bytes32(0);
bool isCollateral = collateralManager().hasCollateral(msg.sender);
bool isEtherWrapper = msg.sender == address(etherWrapper());
bool isWrapper = msg.sender == address(wrapperFactory());

require(isExchanger || isSynth || isCollateral || isEtherWrapper, "Only Internal Contracts");
require(isExchanger || isSynth || isCollateral || isEtherWrapper || isWrapper, "Only Internal Contracts");
_;
}

Expand Down
27 changes: 27 additions & 0 deletions contracts/MixinSystemSettings.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ contract MixinSystemSettings is MixinResolver {
bytes32 internal constant SETTING_ETHER_WRAPPER_MAX_ETH = "etherWrapperMaxETH";
bytes32 internal constant SETTING_ETHER_WRAPPER_MINT_FEE_RATE = "etherWrapperMintFeeRate";
bytes32 internal constant SETTING_ETHER_WRAPPER_BURN_FEE_RATE = "etherWrapperBurnFeeRate";
bytes32 internal constant SETTING_WRAPPER_MAX_TOKEN_AMOUNT = "wrapperMaxTokens";
bytes32 internal constant SETTING_WRAPPER_MINT_FEE_RATE = "wrapperMintFeeRate";
bytes32 internal constant SETTING_WRAPPER_BURN_FEE_RATE = "wrapperBurnFeeRate";
bytes32 internal constant SETTING_MIN_CRATIO = "minCratio";
bytes32 internal constant SETTING_NEW_COLLATERAL_MANAGER = "newCollateralManager";
bytes32 internal constant SETTING_INTERACTION_DELAY = "interactionDelay";
Expand Down Expand Up @@ -143,6 +146,30 @@ contract MixinSystemSettings is MixinResolver {
return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ETHER_WRAPPER_BURN_FEE_RATE);
}

function getWrapperMaxTokenAmount(address wrapper) internal view returns (uint) {
return
flexibleStorage().getUIntValue(
SETTING_CONTRACT_NAME,
keccak256(abi.encodePacked(SETTING_WRAPPER_MAX_TOKEN_AMOUNT, wrapper))
);
}

function getWrapperMintFeeRate(address wrapper) internal view returns (int) {
return
flexibleStorage().getIntValue(
SETTING_CONTRACT_NAME,
keccak256(abi.encodePacked(SETTING_WRAPPER_MINT_FEE_RATE, wrapper))
);
}

function getWrapperBurnFeeRate(address wrapper) internal view returns (int) {
return
flexibleStorage().getIntValue(
SETTING_CONTRACT_NAME,
keccak256(abi.encodePacked(SETTING_WRAPPER_BURN_FEE_RATE, wrapper))
);
}

function getMinCratio(address collateral) internal view returns (uint) {
return
flexibleStorage().getUIntValue(
Expand Down
16 changes: 12 additions & 4 deletions contracts/MultiCollateralSynth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "./Synth.sol";
// Internal references
import "./interfaces/ICollateralManager.sol";
import "./interfaces/IEtherWrapper.sol";
import "./interfaces/IWrapperFactory.sol";

// https://docs.synthetix.io/contracts/source/contracts/multicollateralsynth
contract MultiCollateralSynth is Synth {
Expand All @@ -15,6 +16,7 @@ contract MultiCollateralSynth is Synth {

bytes32 private constant CONTRACT_COLLATERALMANAGER = "CollateralManager";
bytes32 private constant CONTRACT_ETHER_WRAPPER = "EtherWrapper";
bytes32 private constant CONTRACT_WRAPPER_FACTORY = "WrapperFactory";

/* ========== CONSTRUCTOR ========== */

Expand All @@ -39,11 +41,16 @@ contract MultiCollateralSynth is Synth {
return IEtherWrapper(requireAndGetAddress(CONTRACT_ETHER_WRAPPER));
}

function wrapperFactory() internal view returns (IWrapperFactory) {
return IWrapperFactory(requireAndGetAddress(CONTRACT_WRAPPER_FACTORY));
}

function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
bytes32[] memory existingAddresses = Synth.resolverAddressesRequired();
bytes32[] memory newAddresses = new bytes32[](2);
bytes32[] memory newAddresses = new bytes32[](3);
newAddresses[0] = CONTRACT_COLLATERALMANAGER;
newAddresses[1] = CONTRACT_ETHER_WRAPPER;
newAddresses[2] = CONTRACT_WRAPPER_FACTORY;
addresses = combineArrays(existingAddresses, newAddresses);
}

Expand All @@ -69,17 +76,18 @@ contract MultiCollateralSynth is Synth {

/* ========== MODIFIERS ========== */

// Contracts directly interacting with multiCollateralSynth to issue and burn
// Contracts directly interacting with multiCollateralSynth or wrapper to issue and burn
modifier onlyInternalContracts() {
bool isFeePool = msg.sender == address(feePool());
bool isExchanger = msg.sender == address(exchanger());
bool isIssuer = msg.sender == address(issuer());
bool isEtherWrapper = msg.sender == address(etherWrapper());
bool isWrapper = wrapperFactory().isWrapper(msg.sender);
bool isMultiCollateral = collateralManager().hasCollateral(msg.sender);

require(
isFeePool || isExchanger || isIssuer || isEtherWrapper || isMultiCollateral,
"Only FeePool, Exchanger, Issuer, MultiCollateral contracts allowed"
isFeePool || isExchanger || isIssuer || isEtherWrapper || isWrapper || isMultiCollateral,
"Only FeePool, Exchanger, Issuer, Wrapper, or MultiCollateral contracts allowed"
);
_;
}
Expand Down
Loading

0 comments on commit 25c2c61

Please sign in to comment.