Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
280 changes: 105 additions & 175 deletions contracts/ExchangeRates.sol

Large diffs are not rendered by default.

8 changes: 1 addition & 7 deletions contracts/ExchangeRatesWithDexPricing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,7 @@ contract ExchangeRatesWithDexPricing is ExchangeRates {

bytes32 internal constant SETTING_DEX_PRICE_AGGREGATOR = "dexPriceAggregator";

constructor(
address _owner,
address _oracle,
address _resolver,
bytes32[] memory _currencyKeys,
uint[] memory _newRates
) public ExchangeRates(_owner, _oracle, _resolver, _currencyKeys, _newRates) {}
constructor(address _owner, address _resolver) public ExchangeRates(_owner, _resolver) {}

/* ========== SETTERS ========== */

Expand Down
101 changes: 93 additions & 8 deletions contracts/Exchanger.sol
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,13 @@ contract Exchanger is Owned, MixinSystemSettings, IExchanger {
entry.roundIdForDest
);

_ensureCanExchange(sourceCurrencyKey, sourceAmount, destinationCurrencyKey);
_ensureCanExchangeAtRound(
sourceCurrencyKey,
sourceAmount,
destinationCurrencyKey,
entry.roundIdForSrc,
entry.roundIdForDest
);

// SIP-65: Decentralized Circuit Breaker
// mutative call to suspend system if the rate is invalid
Expand All @@ -470,7 +476,12 @@ contract Exchanger is Owned, MixinSystemSettings, IExchanger {
return (0, 0, IVirtualSynth(0));
}

entry.exchangeFeeRate = _feeRateForExchange(sourceCurrencyKey, destinationCurrencyKey);
entry.exchangeFeeRate = _feeRateForExchangeAtRound(
sourceCurrencyKey,
destinationCurrencyKey,
entry.roundIdForSrc,
entry.roundIdForDest
);

amountReceived = _deductFeesFromAmount(entry.destinationAmount, entry.exchangeFeeRate);
// Note: `fee` is denominated in the destinationCurrencyKey.
Expand Down Expand Up @@ -620,6 +631,26 @@ contract Exchanger is Owned, MixinSystemSettings, IExchanger {
require(!exchangeRates().anyRateIsInvalid(synthKeys), "Src/dest rate invalid or not found");
}

function _ensureCanExchangeAtRound(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
uint roundIdForSrc,
uint roundIdForDest
) internal view {
require(sourceCurrencyKey != destinationCurrencyKey, "Can't be same synth");
require(sourceAmount > 0, "Zero amount");

bytes32[] memory synthKeys = new bytes32[](2);
synthKeys[0] = sourceCurrencyKey;
synthKeys[1] = destinationCurrencyKey;

uint[] memory roundIds = new uint[](2);
roundIds[0] = roundIdForSrc;
roundIds[1] = roundIdForDest;
require(!exchangeRates().anyRateIsInvalidAtRound(synthKeys, roundIds), "Src/dest rate invalid or not found");
}

function _isSynthRateInvalid(bytes32 currencyKey, uint currentRate) internal view returns (bool) {
if (currentRate == 0) {
return true;
Expand Down Expand Up @@ -771,6 +802,31 @@ contract Exchanger is Owned, MixinSystemSettings, IExchanger {
return _calculateFeeRateFromExchangeSynths(baseRate, sourceCurrencyKey, destinationCurrencyKey);
}

/// @notice Calculate the exchange fee for a given source and destination currency key
/// @param sourceCurrencyKey The source currency key
/// @param destinationCurrencyKey The destination currency key
/// @param roundIdForSrc The round id of the source currency.
/// @param roundIdForDest The round id of the target currency.
/// @return The exchange fee rate
/// @return The exchange dynamic fee rate
function _feeRateForExchangeAtRound(
bytes32 sourceCurrencyKey,
bytes32 destinationCurrencyKey,
uint roundIdForSrc,
uint roundIdForDest
) internal view returns (uint exchangeFeeRate) {
// Get the exchange fee rate as per destination currencyKey
uint baseRate = getExchangeFeeRate(destinationCurrencyKey);
return
_calculateFeeRateFromExchangeSynthsAtRound(
baseRate,
sourceCurrencyKey,
destinationCurrencyKey,
roundIdForSrc,
roundIdForDest
);
}

function _calculateFeeRateFromExchangeSynths(
uint exchangeFeeRate,
bytes32 sourceCurrencyKey,
Expand All @@ -786,19 +842,48 @@ contract Exchanger is Owned, MixinSystemSettings, IExchanger {
return exchangeFeeRate;
}

function _calculateFeeRateFromExchangeSynthsAtRound(
uint exchangeFeeRate,
bytes32 sourceCurrencyKey,
bytes32 destinationCurrencyKey,
uint roundIdForSrc,
uint roundIdForDest
) internal view returns (uint) {
uint exchangeDynamicFeeRate = _getDynamicFeeForExchangeAtRound(destinationCurrencyKey, roundIdForDest);
exchangeDynamicFeeRate = exchangeDynamicFeeRate.add(
_getDynamicFeeForExchangeAtRound(sourceCurrencyKey, roundIdForSrc)
);
uint maxDynamicFee = getExchangeMaxDynamicFee();

exchangeFeeRate = exchangeFeeRate.add(exchangeDynamicFeeRate);
// Cap to max exchange dynamic fee
exchangeFeeRate = exchangeFeeRate > maxDynamicFee ? maxDynamicFee : exchangeFeeRate;
return exchangeFeeRate;
}

/// @notice Get dynamic fee for a given currency key (SIP-184)
/// @param currencyKey The given currency key
/// @return The dyanmic fee
function _getDynamicFeeForExchange(bytes32 currencyKey) internal view returns (uint dynamicFee) {
// No dynamic fee for sUSD
if (currencyKey == sUSD) {
return 0;
}
if (currencyKey == sUSD) return 0;
(uint threshold, uint weightDecay, uint rounds) = getExchangeDynamicFeeData();
uint[] memory prices;
uint roundId = exchangeRates().getCurrentRoundId(currencyKey);
(prices, ) = exchangeRates().ratesAndUpdatedTimeForCurrencyLastNRounds(currencyKey, rounds, roundId);
dynamicFee = DynamicFee.getDynamicFee(prices, threshold, weightDecay);
}

/// @notice Get dynamic fee for a given currency key (SIP-184)
/// @param currencyKey The given currency key
/// @param roundId The round id
/// @return The dyanmic fee
function _getDynamicFeeForExchangeAtRound(bytes32 currencyKey, uint roundId) internal view returns (uint dynamicFee) {
// No dynamic fee for sUSD
if (currencyKey == sUSD) return 0;
(uint threshold, uint weightDecay, uint rounds) = getExchangeDynamicFeeData();
uint[] memory prices;
// Note: We are using cache round ID here for cheap read
uint currentRoundId = exchangeRates().currentRoundForRate(currencyKey);
(prices, ) = exchangeRates().ratesAndUpdatedTimeForCurrencyLastNRounds(currencyKey, rounds, currentRoundId);
(prices, ) = exchangeRates().ratesAndUpdatedTimeForCurrencyLastNRounds(currencyKey, rounds, roundId);
dynamicFee = DynamicFee.getDynamicFee(prices, threshold, weightDecay);
}

Expand Down
4 changes: 1 addition & 3 deletions contracts/interfaces/IExchangeRates.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface IExchangeRates {

function anyRateIsInvalid(bytes32[] calldata currencyKeys) external view returns (bool);

function currentRoundForRate(bytes32 currencyKey) external view returns (uint);
function anyRateIsInvalidAtRound(bytes32[] calldata currencyKeys, uint[] calldata roundIds) external view returns (bool);

function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory);

Expand Down Expand Up @@ -85,8 +85,6 @@ interface IExchangeRates {

function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256);

function oracle() external view returns (address);

function rateAndTimestampAtRound(bytes32 currencyKey, uint roundId) external view returns (uint rate, uint time);

function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint rate, uint time);
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IExchanger.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity >=0.4.24;
pragma solidity ^0.5.16;

import "./IVirtualSynth.sol";

Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IFlexibleStorage.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity >=0.4.24;
pragma solidity ^0.5.16;

// https://docs.synthetix.io/contracts/source/interfaces/iflexiblestorage
interface IFlexibleStorage {
Expand Down
1 change: 1 addition & 0 deletions hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,6 @@ module.exports = {
},
mocha: {
timeout: 120e3, // 120s
retries: 3,
},
};
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,8 @@ const defaults = {
},

ETHER_WRAPPER_MAX_ETH: w3utils.toWei('5000'),
ETHER_WRAPPER_MINT_FEE_RATE: w3utils.toWei('0.02'), // 200 bps
ETHER_WRAPPER_BURN_FEE_RATE: w3utils.toWei('0.0005'), // 5 bps
ETHER_WRAPPER_MINT_FEE_RATE: w3utils.toWei('0.005'), // 5 bps
ETHER_WRAPPER_BURN_FEE_RATE: '0',

// SIP-120
ATOMIC_MAX_VOLUME_PER_BLOCK: w3utils.toWei(`${2e5}`), // 200k
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "synthetix",
"version": "2.55.0",
"version": "2.56.1",
"license": "MIT",
"author": "Synthetix",
"description": "The smart contracts which make up the Synthetix system. (synthetix.io)",
Expand All @@ -18,7 +18,7 @@
"prepublishOnly": "npm run describe && npm run pack",
"fork": "node --max-old-space-size=4096 ./node_modules/.bin/hardhat node",
"fork:mainnet": "node --max-old-space-size=4096 ./node_modules/.bin/hardhat node --target-network mainnet",
"test": "hardhat test",
"test": "node --max-old-space-size=4096 ./node_modules/.bin/hardhat test",
"describe": "hardhat describe",
"test:deployments": "mocha test/deployments -- --timeout 60000",
"test:etherscan": "node test/etherscan",
Expand Down
6 changes: 6 additions & 0 deletions publish/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@
"sign": "",
"description": "DeFi Index"
},
"ETHBTC": {
"asset": "ETHBTC",
"category": "crypto",
"sign": "",
"description": "ETH / BTC"
},
"EUR": {
"asset": "EUR",
"category": "forex",
Expand Down
3 changes: 3 additions & 0 deletions publish/deployed/kovan-ovm/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,8 @@
},
"OwnerRelayOnOptimism": {
"deploy": false
},
"CollateralEth": {
"deploy": false
}
}
1,335 changes: 1,291 additions & 44 deletions publish/deployed/kovan-ovm/deployment.json

Large diffs are not rendered by default.

11 changes: 10 additions & 1 deletion publish/deployed/kovan-ovm/params.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"SHORTS": ["sBTC", "sETH", "sLINK", "sUNI", "sAAVE"],
"MAX_DEBT": "75000000000000000000000000",
"MAX_SKEW_RATE": "200000000000000000",
"BASE_BORROW_RATE": "158443823",
"BASE_BORROW_RATE": "950662938",
"BASE_SHORT_RATE": "158443823"
}
},
Expand All @@ -32,5 +32,14 @@
"INTERACTION_DELAY": "0",
"COLLAPSE_FEE_RATE": "0"
}
},
{
"name": "COLLATERAL_ETH",
"value": {
"SYNTHS": ["sUSD"],
"MIN_CRATIO": "1200000000000000000",
"MIN_COLLATERAL": "100000000000000000",
"ISSUE_FEE_RATE": "0"
}
}
]
41 changes: 39 additions & 2 deletions publish/deployed/kovan-ovm/versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -778,8 +778,9 @@
},
"Synthetix": {
"address": "0xCAA5c8e9E67BBa010D2D7F589F02d588Fb49f93D",
"status": "current",
"keccak256": "0xbbe79669c2586e5f0a7f35a0577d21b881e0e083b9fc297fa16d6c1de064c749"
"status": "replaced",
"keccak256": "0xbbe79669c2586e5f0a7f35a0577d21b881e0e083b9fc297fa16d6c1de064c749",
"replaced_in": "v2.56.0-alpha"
},
"DebtCache": {
"address": "0xCF4a31F3C7E245F8de884907aEFF1841C042cF41",
Expand Down Expand Up @@ -967,5 +968,41 @@
"keccak256": "0x582cac91f50cfefc154d67097081d0dd0d4877333df51c3cfe19485f80ef7e74"
}
}
},
"v2.56.0-alpha": {
"tag": "v2.56.0-alpha",
"fulltag": "v2.56.0-alpha",
"release": "Alhena",
"network": "kovan",
"date": "2021-12-07T16:13:13-05:00",
"commit": "79b5acd4a4557d9892409dad70f139f54cf5e6d5",
"contracts": {
"Synthetix": {
"address": "0x752b2e77769a8832E657CB9f7318543e03c13627",
"status": "replaced",
"keccak256": "0x87c92d55af4f4b01932ec25770439770836ed60b9652a3f4ab1ec6e0d82d302a",
"replaced_in": "v2.56.1-alpha"
}
}
},
"v2.56.1-alpha": {
"tag": "v2.56.1-alpha",
"fulltag": "v2.56.1-alpha",
"release": "Alhena",
"network": "kovan",
"date": "2021-12-15T05:19:57-05:00",
"commit": "64f28868700af3cbc1fae6522d7fd29d059d7577",
"contracts": {
"Synthetix": {
"address": "0x099B3881d63d3Eef0ec32783Aa64B726672213E2",
"status": "current",
"keccak256": "0x87c92d55af4f4b01932ec25770439770836ed60b9652a3f4ab1ec6e0d82d302a"
},
"CollateralEth": {
"address": "0xc7960401a5Ca5A201d41Cf6532C7d2803f8D5Ce4",
"status": "current",
"keccak256": "0xd83c3667bcacd4d33cf0fc649cee03d85e7d3914abb7ce6c9898e6ee1d66da81"
}
}
}
}
11 changes: 10 additions & 1 deletion publish/deployed/local-ovm/params.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"SHORTS": ["sBTC", "sETH"],
"MAX_DEBT": "75000000000000000000000000",
"MAX_SKEW_RATE": "200000000000000000",
"BASE_BORROW_RATE": "158443823",
"BASE_BORROW_RATE": "950662938",
"BASE_SHORT_RATE": "158443823"
}
},
Expand All @@ -32,5 +32,14 @@
"INTERACTION_DELAY": "0",
"COLLAPSE_FEE_RATE": "0"
}
},
{
"name": "COLLATERAL_ETH",
"value": {
"SYNTHS": ["sUSD"],
"MIN_CRATIO": "1200000000000000000",
"MIN_COLLATERAL": "100000000000000000",
"ISSUE_FEE_RATE": "0"
}
}
]
3 changes: 3 additions & 0 deletions publish/deployed/mainnet-ovm/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 +160,8 @@
},
"OwnerRelayOnOptimism": {
"deploy": false
},
"CollateralEth": {
"deploy": false
}
}
Loading