Skip to content

SIP-184: Remove currentRound auto incrementation from ExchangeRates#1630

Closed
leckylao wants to merge 8 commits intofeat/sip-184-dynamic-feesfrom
fix/remove-current-round-auto-incrementation
Closed

SIP-184: Remove currentRound auto incrementation from ExchangeRates#1630
leckylao wants to merge 8 commits intofeat/sip-184-dynamic-feesfrom
fix/remove-current-round-auto-incrementation

Conversation

@leckylao
Copy link
Copy Markdown
Contributor

  • setting sUSD on constructor;
  • moved currentRound auto increment into internalUpdateRates

@codecov
Copy link
Copy Markdown

codecov bot commented Dec 11, 2021

Codecov Report

Merging #1630 (07807d5) into feat/sip-184-dynamic-fees (e905aca) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@                    Coverage Diff                     @@
##           feat/sip-184-dynamic-fees    #1630   +/-   ##
==========================================================
  Coverage                      95.73%   95.74%           
==========================================================
  Files                             83       83           
  Lines                           1945     1949    +4     
  Branches                         609      610    +1     
==========================================================
+ Hits                            1862     1866    +4     
  Misses                            83       83           
Impacted Files Coverage Δ
contracts/ExchangeRates.sol 100.00% <100.00%> (ø)
contracts/Exchanger.sol 96.80% <100.00%> (+0.14%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e905aca...07807d5. Read the comment docs.

@jjgonecrypto jjgonecrypto changed the title fix(ExchangeRates): Remove currentRound auto incrementation SIP-184: Remove currentRound auto incrementation from ExchangeRates Dec 13, 2021
Copy link
Copy Markdown
Contributor

@artdgn artdgn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was sure we said that removing the curreRate state variable is the best course of action.

The only place it's used right now is the exchanger for getting the last cached rate for dynamic fee to get the correct set of prices. It can be removed there because you already have the roundIds in the _exchange method that you can pass into the fees method to get the historic prices.

This way, this whole issue with coupling, and incrementing, etc can be avoided.

// The sUSD rate is always 1 and is never stale.
_setRate("sUSD", 0, SafeDecimalMath.unit(), now);
// The sUSD rate is always 1 on round 1 and is never stale.
currentRoundForRate["sUSD"]++;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can be just = 1 probably

(sourceRate, time) = _getRateAndTimestampAtRound(sourceCurrencyKey, roundIdForSrc);
// cacheing to save external call
_setRate(sourceCurrencyKey, roundIdForSrc, sourceRate, time);
if (sourceCurrencyKey != "sUSD") _setRate(sourceCurrencyKey, roundIdForSrc, sourceRate, time);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the != sUSD check should probably me moved into the _setRate method to avoid the duplicate code and inline ifs. It's probably belongs there anyway because that's the method that has handles the caching and knows how sUSD rate should be cached.

nit: I'd prefer to avoid inline ifs, they're easy to miss when reading, so impact readability and clarity. Aren't used in other places in code. [If there are too many blocks due to nested ifs, it probably means that the code is written in a complex way and is doing too many things and can be refactored, shortening the syntax is only making it worse IMO]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does has the != sUSD check in _setRate, here is when reading the sUSD rate don't try to set it. Will put a comment there.

Copy link
Copy Markdown
Contributor

@artdgn artdgn Dec 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to remove the require in _setRate, and instead just return if it's sUSD.

So in _setRate instead of this:

require(currencyKey != "sUSD", "Rate of sUSD cannot be updated, it's always UNIT.");

maybe replace with this:

if (currencyKey == "sUSD") {
  // no caching is done for sUSD
  return;
}

This way, there is no need to have those ifs elsewhere and:

  • code is easier to read (less ifs)
  • whoever is calling setRate doesn't need to check the currency

Also, nit: "sUSD" should probably be a named constant.

require(currencyKey != "sUSD", "Rate of sUSD cannot be updated, it's always UNIT.");
require(roundId > 0, "Round id must be greater than 0.");

currentRoundForRate[currencyKey] = roundId;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was under the impression that we've agreed that currentRoundForRate should be removed because it introduces more risks, potential for bugs, and too much coupling (between rates and exchanger contract).

Copy link
Copy Markdown
Contributor Author

@leckylao leckylao Dec 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the first iteration. And currentRoundForRate is more for improvement due to the tightly coupled code and timeframe.

- Using constant for sUSD;
- no cache for sUSD in setRate
@leckylao
Copy link
Copy Markdown
Contributor Author

I was sure we said that removing the curreRate state variable is the best course of action.

The only place it's used right now is the exchanger for getting the last cached rate for dynamic fee to get the correct set of prices. It can be removed there because you already have the roundIds in the _exchange method that you can pass into the fees method to get the historic prices.

This way, this whole issue with coupling, and incrementing, etc can be avoided.

Yes, it's pretty much doing the same, instead of creating more params in order to pass in the roundId, it's just reusing the currentRoundForRate that just set by the mutativeEffectiveValueAndRatesAtRound.

@leckylao leckylao requested a review from artdgn December 13, 2021 13:12
Copy link
Copy Markdown
Contributor

@artdgn artdgn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great, now that currentRoundForRate is not used, I think it should be possible to remove it also from the ExchangeRates contract.

returns (uint exchangeFeeRate)
{
exchangeFeeRate = _feeRateForExchange(sourceCurrencyKey, destinationCurrencyKey);
exchangeFeeRate = _feeRateForExchange(sourceCurrencyKey, destinationCurrencyKey, 0, 0);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you're using 0, 0 to mean latest rounds. I think it's better to use the correct latestRounds here, and avoid having special logic for 0 there. Less implicit special logic for special values will reduce edge cases and surface area for bugs (explicit > implicit).

Alternatively you can create another method that doesn't expect roundId numbers: _feeRateForExchangeLatestRounds that doesn't expect roundIds and get them from exchangeRates.

// Note: We are using cache round ID here for cheap read
uint currentRoundId = exchangeRates().currentRoundForRate(currencyKey);
(prices, ) = exchangeRates().ratesAndUpdatedTimeForCurrencyLastNRounds(currencyKey, rounds, currentRoundId);
if (roundId == 0) roundId = exchangeRates().getCurrentRoundId(currencyKey);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this method should try to be smart about the roundId it's getting. It's better to avoid using 0 as a special case if we can. This will reduce coupling, edge cases, and surface area for bugs. This method should just work with the roundId it's getting IMO because it's a low level method.

)
{
exchangeFeeRate = _feeRateForExchange(sourceCurrencyKey, destinationCurrencyKey);
exchangeFeeRate = _feeRateForExchange(sourceCurrencyKey, destinationCurrencyKey, 0, 0);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above.

- Using level method to avoid explicite condition
@jjgonecrypto
Copy link
Copy Markdown
Contributor

Closed in favor of #1649

@jjgonecrypto jjgonecrypto deleted the fix/remove-current-round-auto-incrementation branch January 18, 2022 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants