Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Exchange.sol] make bucket updates from Oracle data more predictable #4096

Closed
zviadm opened this issue Jun 13, 2020 · 9 comments
Closed

[Exchange.sol] make bucket updates from Oracle data more predictable #4096

zviadm opened this issue Jun 13, 2020 · 9 comments
Labels

Comments

@zviadm
Copy link
Contributor

zviadm commented Jun 13, 2020

Currently there is no easy way to tell if gold and stable token buckets will or will not get updated in next block.

When you call getBuyAndSellBuckets it might think that there won't be a bucket update from oracle data because it can't know what the now timestamp will be in next block.

This can lead to a confusion when getBuyAndSellBuckets returns incorrect buckets compared to what will actually be used in the next block.

It would be great if these updates can be made more predictable. Instead of updating buckets in the same block when calling 'updateBucketsIfNecessary', it could first just mark the buckets for updating for next block.
This would simplify getBuyAndSellBuckets because it would only need to check that marker, instead of running the whole shouldUpdateBuckets logic, and this would also remove the dependency on now timestamp in that code path.

This type of change would make it predictable to know what the starting [gold, stable] buckets will be in next block, instead of current setup where there is no way to know if oracle update will or will not be applied in next block.

@haferman
Copy link

This I believe is related so I'll add it here: I'm seeing that the value of lastBucketUpdate is often not updated even when the values of the [gold, stable] buckets are updated.

@zviadm
Copy link
Contributor Author

zviadm commented Jun 15, 2020

This I believe is related so I'll add it here: I'm seeing that the value of lastBucketUpdate is often not updated even when the values of the [gold, stable] buckets are updated.

this is because lastBucketUpdate only gets updated when a successful trade is made. if no trades are happening buckets never actually get updated and getBuyAndSellBuckets will just read oracle reported values everytime. And next trade will always use last oracle reported values too.

Basically uniswap mechanism doesn't reset every updateFrequency. It only resets if successful trade happens after updateFrequency amount of time has passed after last reset.

@tkporter
Copy link
Contributor

Thanks for opening this! When building the oracle client it was also found the existing reliance on timestamp was very annoying. In an ideal world, oracle rates would be reported as close to the bucket update time as possible to conserve gas spending and ensure the median rate at a bucket update is new, and the timestamp added a degree of uncertainty. cc @rcroessmann

@haferman
Copy link

haferman commented Jun 15, 2020

this is because lastBucketUpdate only gets updated when a successful trade is made. if no trades are happening buckets never actually get updated and getBuyAndSellBuckets will just read oracle reported values everytime. And next trade will always use last oracle reported values too.

I understand this. But I observed trades being placed and lastBucketUpdate not being updated.

UPDATE: OK, it was explained to me that these numbers are only affected by on-chain transactions, not exchange transactions.

@zviadm
Copy link
Contributor Author

zviadm commented Sep 21, 2020

@tkporter fyi, this issue is even more relevant now that Oracle circuit breaker has triggered twice. The "re-enabling" of oracles, after they have been down, is basically a completely unpredictable event right now that puts arbitrageurs at a risk. Re-enabling oracles event can cause a large unpredictable change in exchange rate within a block, and there is no way to predict or observe that it is about to happen. So it creates a large risk for one sided arbitrage trades to happen because of it.

In general, safer arbitrage ==> more efficient protocol, so if changes can be made that makes arbitrage safer it will only help protocol be more efficient overall.

@tkporter
Copy link
Contributor

@zviadm is setting a conservative minBuyAmount not enough to protect yourself?
If it doesn't protect you enough I'd think that arbitrageurs would prefer to have their tx revert in the event that the price has changed dramatically. This could be done with a helper contract that calls Exchange.sol but also has more strict checks and wouldn't require changes to the protocol directly

@zviadm
Copy link
Contributor Author

zviadm commented Sep 21, 2020

@tkporter it of course depends which direction arbitrageur does trades in first. If they do "on-chain" trade first, they avoid this issue, but it introduces other issues. Since "on-chain" trades are quite slow and CEX market is more efficient overall, arbitrageur risks pretty high slippage for their CEX trades. To operate this way, arbitrageur has to wait for a very large profit gap before initiating trades to cover for the risk. So this is possible, but it is not great for protocol since this would be pretty inefficient.

If arbitrageur trades on CEX first, and trades "on-chain" second, this generally gives more safety. When exchange is in "uniswap mode", exchange rate on-chain is much more predictable and there are much lower chances of huge slippages to happen. (i.e. a slippage of 1-2% can happen, but slippage of 10-20% is extremely unlikely).

Except for in circumstances like this. This type of unpredictable sudden oracle update can cause huge slippage for exchange rate within a block (last one caused ~18% change in exchange rate in a single block). Worst part of course is that the re-enabling event is completely unpredictable. If there was a signal one block before that an update is coming, that would make things safer since trades can be avoided until price is updated and can be resumed safely afterwards once again.

Just to note, this 're-enabling' event is more unpredictable than regular "every 5 minute updates". This is because regular updates can be at predicted since you can always know how long has passed since the last bucket update, and it is not too complex to skip trading around the block which will most likely involve a bucket update.

@zviadm
Copy link
Contributor Author

zviadm commented Sep 21, 2020

Thinking about this some more, my initial thought might have been incorrect and the "re-enabling" event probably doesn't increase risk that significantly. While it would be nice if oracle updates were more predictable, there are other risk factors (like someone else making a huge single trade when "on-chain" price is significantly off), that it probably wouldn't change overall risk of slippage significantly anyways.

@github-actions
Copy link
Contributor

This issue is stale and will be closed in 30 days without activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants