Rounding fix for yxTokens
TL;DR: yxTokens had a rounding issue that would have caused the mint of 1e-18 (1 wei) more than what was registered in dYdX contract. We released the new version of yxDAI and yxUSDC with the issue fixed. You can find the new deployed addresses here.
On May 28th our system was trying to perform a routine rebalance on idleDAI (best yield strategy) and we noticed that the gas estimation of the transaction was failing.
We immediately spin up a fork of the mainnet locally using Ganache to test what was going on and the transaction was failing with an ‘Undercollateralized account’ error. This was a dYdX error.
We contacted dYdX team and after a quick chat with Brendan Chou, we discovered the following: idleDAI contract was trying to move (for the first time) everything out from dYdX, because of an interests rates’ variation, and we were trying to move 19715843081367274386798 yxDAI (in wei) but we only had 19715843081367274386731 of equivalent value registered in the dYdX contract, so there was a 67 wei difference.
Why this difference? The problem was in the implementation of our yxToken contract, used to tokenize lending positions on dYdX. When calling mint we were calculating the amount of yxTokens using a price reference which was a simple call to dYdX ‘currentMarketIndex’ method to get the conversion rate between dYdX’s Wei and Par concepts.
The flow was conceptually correct, but the problem was that during those calculations we were effectively depositing 1 wei less each time that amount/price was resulting in a floating-point number. Therefore Solidity was effectively truncating down the amount we were depositing, hence the rounding issue.
To safely unlock the situation we redeemed everything from dYdX except 1/100000th of the total AUM of idleDAI Best strategy (allocations in Idle range from 0 to 100000) so we left ~2.32 DAI at that time in dYdX. We then modified our off-chain system to always leave at least 0.00001% of the total AUM in dYdX.
No one besides us was already using yxTokens in production, given that is being announced exactly 2 weeks ago.
The fix is pretty simple: we avoid performing any calculations in yxToken contract, we simply get the Par value of yxToken contract in the dYdX Solo contract before executing the mint operation, and then we get the value another time right after the mint so to have the exact same value registered in dYdX contract. During redeem, we directly send the Par value (yxToken balance) instead of calculating the Wei value using the current price. You can see the diff here.
We have now deployed a new version of yxDAI and yxUSDC, so if you plan to use yxTokens those are the new addresses:
More information here: https://developers.idle.finance/advanced/yxtoken-dydx-tokenization
What does it mean for Idle?
To sum up: 0.00001% of the funds of idleDAI and idleUSDC under specific circumstances (ie when dYdX should not have funds allocated at all) instead of getting the highest interest rate, they are ‘only’ getting the dYdX interest rate.
Even if this amount can seem negligible, we want to keep the efficiency of our pools. To mitigate it, we will take care of this opportunity cost.
Currently, the biggest pool, idleDAI Best Yield, has about 240k DAI in the pool. This means that only 2.4 DAI could potentially not always getting the highest interest rate, even if we suppose a worst-case scenario where dYdX is underperforming the highest apr of 5% for an entire year, the opportunity cost would be abysmal, around 0.12 DAI per year, 0.01 DAI per month.
We will cover this opportunity cost by sending the equivalent amount directly into the pool, once a month.
Keep yourself updated
We’re building Idle for the Ethereum ecosystem and its great community. We’d love for you to be part of our development process. Here you can find our documentation: https://developers.idle.finance.
To follow our updates, new releases, and monthly reports, subscribe to our newsletter.