Zero premine protocols have shown up with force, letting loose upon the world fledgling un-audited code with no premine. Meanwhile, the devs continue building the thing while flying through metaphorical blockchain thunderstorms. Think test piloting but with software, a rapidly growing, hyperventilating user base, and a deluge of cash (lest we forget the prime defi metric: Total Value Locked (TVL)).
FYI (or YFI??): YAM TVL was $563,111,070 as of 10pm August 12th. I don't even know the zenith of TVL for the YAM protocol in its short lived reign.
We're now two days post YAM kickoff and a bug has been discovered in the rebasing contract. There is an all out effort to mobilize the nascent farming community to pass a proposal to secure our beloved yam protocol. As I sit here writing this, there's a collective 2,132,840 (worth $48,021,103) UNIV2 tokens stacked in YAM's UNIV2 staking pool.
We're flying the plane while building, so lets paraphrase from this post: https://medium.com/@yamfinance/save-yam-245598d81cec
My familiarity with the contract code base is quite literally me writing this as I walk through the github repo.
There is a bug in the
rebase function of the
Link to start of rebase function: https://github.com/yam-finance/yam-protocol/blob/d10780268273fb4d97fae8a549ab22e4bb35e426/contracts/token/YAM.sol#L313
totalSupply = initSupply.mul(yamsScalingFactor);
As the author alluded to in the earlier post, should be:
totalSupply = initSupply.mul(yamsScalingFactor).div(BASE);
initSupply is multiplied by the
yamsScalingFactor but was not divided by the
BASE constant. In Maker parlance,
10 ** 18).
When the YAM token was initialized,
yamsScalingFactor was set to
BASE (remember: 10 ** 18). Line 340 takes
initSupply and multiplies it by the this 18 digit uint, but fails to then divide by it.
In terms of arbitrary precision, here is the
BASE constant value:
initSupply was multiplied by this large
uint but not divided. It is a precision error.
Pretend we initialized with an
1337, then it's easier to see the impact (and I'll even use a precision calculator for appropriate measure):
With the precision error bug:
bc -l <<< ' 1337 * 10 ^ 18 ')
Without the precision error bug:
bc -l <<< ' 1337 * 10 ^ 18 / 10 ^ 18')
Other noteworthy things
Only the Rebaser contract can call the
yam.rebase() function. Also worth a mention is that only an Externally Owned Address (EOA) can call the
rebaser.rebase() function, as enforced by the
require(msg.sender == tx.origin) on line 309.
The initial rebase occurred at 7AM UTC August 12th and resulted in roughly $500k worth of yCRV being added to the YAM treasury. Any governance issue to rectify the hyper-inflating treasury supply must happen in the 12 hour window before the next rebase.
Mobilizing the community
To continue with the aviation analogies, we're mid-flight at about 10,000 ft (we never got to cruising altitude) and there's a fire in one engine. A manageable situation, but we need coordination... and we got coordination.
At this point, I delegated and positioned myself for both possible outcomes.... and went to bed.
While asleep, the community successfully garnered the required number of YAM votes to pass the proposal. I don't have the numbers at the moment, but may update this post with them later.
The delegated votes were secured, and then began the attempt to rescue the governance functionality of the protocol.
13-08-2020 7:12:03 UTC Transaction where the proposal was submitted to the
GovernorAlpha contract: https://ethtx.info/mainnet/0x1d64875b24732bc2e8880cd0870ea8e301ddde683ce81fea418e9ab4feea90bb
My understanding here is that although the community had delegated enough YAM to meet the proposal threshold, there is a timelock feature of the current unix timestamp + 12.5 hours that is tee'd up from when the proposal is queued. And that timelock pushed the ability to propose beyond the second rebase. Once the second rebase happened, there were not enough votes to maintain the 1% threshold set from the imprecise
Then, someone canceled the proposal. Although to be honest, it was already defeated.
13-08-2020 08:21:01 UTC Transaction where the proposal was canceled by an Externally Owned Address: https://ethtx.info/mainnet/0x1b98c761592b54498b9fbd41e6e4755cf6e5a1a6f13658d409081532d89d6bf0
From the Compound docs:
Cancel a proposal that has not yet been executed. The Guardian is the only one who may execute this unless the proposer does not maintain the delegates required to create a proposal. If the proposer does not have more delegates than the proposal threshold, anyone can cancel the proposal.
guardian address of GovernorAlpha contract is set to
address(0) so cancellation by
guardian is not a distinct possibility. In our situation here, the proposer did not have more delegates than the proposal threshold, and as a result anyone can cancel the proposal. And that cancel function was called for reasons unknown to me by an externally owned address:
At this point the cargo plane carrying all our beloved YAMs collided swiftly into the tarmac, and while it didn't go up into a ball of flames, all of our yams got smashed. Perhaps the plane is salvageable, but it's too early to tell, we can only assess the damage.
As @yamfinance explains on their twitter:
"The concern is the same as before: the yCRV accumulated in the reserves during rebase is at risk of being stuck if governance cannot pass proposals." See: https://twitter.com/YamFinance/status/1293814954164981760
In summary, and perhaps I'll do do a deeper analysis of the code, due to our failed landing the rebaser contract will continue minting tons of YAM into the protocol reserve. The YAM treasury will continue to hyper-inflate, permanently hindering any further governance action.
Late last night YAM was trading around ~$12/yam and now on Coingecko it's trading at $0.95/yam. If you're still in the UNI-V2 pool, please grab a parachute and exit immediately.
Main takeaway that is important to me: the community mobilized itself when it mattered and it did so in a 12 hour window, yet the protocol code prevented a timely rescue. We're but mere test pilots and we carry onward researching, implementing, and testing new ways to bootstrap and operate meaningful governance systems.