Upgrade Disclosure: 001 Fixed Inability to Upgrade

Chris Robison
meTokens
Published in
7 min readApr 28, 2020

While attempting to fix a minor bug, we discovered our contract upgradability failed to confirm for meToken Instances due to the tx hitting the block gas limit. Individual meTokens have been redeployed and re-collateralized with the operating funds of the meToken project team members. Users can now use StakeOnMe once again. Functionality for DAOs is temporarily disabled.

What Happened?

In the first week of launch, a number of users and community members reported on the fact that meToken names were not registering correctly on Etherscan or in many of their favorite Ethereum wallets. Instead of displaying their meToken name, these services simply declared “Not Active,” even though the meTokens were, in fact, confirmed to be active and functional.

We quickly identified the source of the problem was a combination of (A) how the creation of a new meToken relies upon 2 transactions, and (B) how these services cache ERC20 data. During creation, the name of a person’s meToken is set in the second transaction. However, when these services see a new ERC20 created, they publish the data immediately with the assumption everything was set in the first transaction.

We began exploring options for how to resolve this in a way that provided the best possible UX. Although it would challenge some of the intentional design choices we made early on, it seemed the best option was to restructure the smart contracts so that meToken names were set in the first transaction.

To accommodate for this, we created and deployed to testnet an updated version of three meToken contracts: (1) the meToken hub, which is responsible for tracking all meTokens; (2) the meToken Individual Factory, which is where new meTokens are minted from; and (3) the meToken individual instance, which is responsible for managing an owner’s ERC20 contract and their bonding curve issuance. It was during the deployment of these updates that we uncovered a critical flaw in our contract’s upgradability.

Critical Flaw

meToken instances hit the block gas limit and failed to upgrade in our tests. While we had previously tested the upgradability of our HUB and Factory contracts on public testnets, our upgrade tests of the Instances had only been run locally.

dApp Architecture

The way that the HUB and Factory contracts upgrade is different than the way Instances are upgrades. Instances are owned entirely by their owner, while the HUB and factory contracts are owned and managed by the project team’s admin key. This restricted our ability to intervene with users’ meTokens entirely.

The non-custodial design of our architecture only allows the project team to (1) change how new meTokens are minted — by updating the HUB or Factory contracts — and (2) suggest how existing meTokens can upgrade. That is to say, we can propose upgrades to users, but owners of existing meTokens make the final decision as to whether or not they will opt-in to a suggested upgrade.

Gas Limit

The upgrade we were testing required users to opt-in. As we began executing upgrades on testnet, we discovered that although the HUB and Factory upgrades confirmed correctly, the Instances were hitting the gas limit.

Upon further inspection, we discovered that migrated Instances were attempting to transfer staked ETH to the new contracts — as they should. However, transferring staked ETH triggered the fallback function in an unique condition that caused the gas to exceed the block limit — something that went unrecognized in our local test.

In effect, this made current meTokens impossible to upgrade. Ever 😢

Solution

We redeployed everything from scratch. If you go to StakeOnMe.com, you will see everything pretty much appears the same. All owners still have their meToken profile pages. And if you have purchased meTokens of other users, your wallets hold the same portfolio of your crypto-friends as before.

The reason everything pretty much looks the same is because we initialized everyone’s meTokens anew, collateralized them with our own operational funds, and airdropped the newly minted meTokens to all the same token holders as before. Of course, when we did this, we also made sure the new contracts were upgradable 😬

Additional Upgrades

In addition to fixing individual meToken upgradability we also pushed the following upgrades:

  • Valid meToken names — all meToken names now appear correctly on etherscan and in all wallets.
  • Only owners can mint meTokens — before the upgrade we allowed users to set meToken ownership to any address. This effectively allowed people to create meTokens for other users. While this is a desirable feature in certain circumstances, it turned out to be undesirable by most users who provided us feedback for this stage of our Alpha. We have set an ‘only msg.sender’ modifier to prevent this while we research the best way to implement a dedicated “other individuals” meToken factory for a future release.
  • Initial ETH Deposit lowered to 0.0001 — previously StakeOnMe required an initial 0.005 ETH deposit to create a new meTokens. This deposit was locked to construct the initial bonding curve parameters (effectively burned). However, we found most users experimented with creating meTokens and staking on other people with amounts close to 0.0005 ETH. As a result, this skewed the sell & burn returns made by the bonding curve. This upgrade provides users with better sell & spend rates.
  • 3Box Bios — to provide more context into meToken profiles, we have now imported bios from 3Box. When you view a person’s meToken, you’ll be able to learn a bit more about them without leaving StakeOnMe.com.
  • USD Oracles — You can now see the value of your meTokens when you go to a person’s meToken profile page. There are two distinct values: (1) the value of your meTokens if you choose to sell them against the curve, and (2) the value of your meTokens if you spend them with their owner.

Consequences

The three main consequences to these upgrades are:

  1. DAO meTokenization is temporarily suspended from the front-end — DAO Instance upgradability, unfortunately, remains infeasible for all DAO-type implementations with our current solution. We will resume DAO meTokenization functionality as soon as we are able to implement and test proper solutions. Full disclosure: we have already begun this process, but do not have an expected timeline.
  2. All contract addresses are different now — The only folks who are affected by the change in contract addresses are those who already configured their ‘stakeonme’ ENS subdomain, as it still points to the old contract. This is easily resolvable, however, and can be managed through the ENS app manually. We have opened a #support channel in our Discord to assist users with this.
  3. All meToken balances are difference now — this is only an aesthetic difference. All balance proportions (pegged to ETH) are still the same. This is a result of changing the initial deposit from 0.005 ETH to 0.0001 ETH. When this happened, the number of meTokens minted by the bonding curve shifted for everybody. In practical terms: if Bob purchased 0.5 Ether worth of a Alice’s legacy meToken, he may have been returned an amount of 1,000. In the new contract, however, Bob instead might’ve received 8,500 of Alice’s meToken. This does not change the amount of ETH that collateralizes Bob’s holdings. His 8,500 new meTokens still have the same underlying 0.5 ETH.

Outliers

In the process of redeploying all the new meTokens, there were a few transactions that were not replicated perfectly:

  • We pruned inactive and duplicate meTokens — there were a small handful of old meTokens that were either never properly initialized in the original contracts or they were duplicated. We did not redeploy either of these types of meTokens.
  • One user deployed some meTokens to Uniswap — this is a very desirable behavior for meTokens and we strongly encourage people to this! Unfortunately, in the process of redeploying, there was no way for us to create a new uniswap pair, create liquidity, and give liquidity ownership to the user who originally deposited the funds. So we instead deposited the remaining liquidity back in the address of the user who acted as the original liquidity provider. Note that some users successfully purchased this particular meToken from Uniswap and that those users were provided with the new meToken replacements, as well.

Takeaways

While the initial implementation of our upgradable contracts failed at our own expense, it is worth noting how our architectural design succeeded. Because the meToken project team members reserve no administrative privileges over user’s meTokens and the funds in them, we were unable to freeze or withdraw any collateral from any of the deployed contracts.

That said… the big question remains: what do we do with all the collateral left in the legacy contracts? Well, we’re sad to say, we don’t have a good answer to that. If we allowed users to access the legacy meToken contracts through our hosted front-end, then it would be a race to the bottom to sell or awkwardly spend the old meTokens. For a myriad of reasons we have decided not to take on this responsibility. And this is why we made the decision to fund the cloned contracts & user states with our own operational funds.

If, in response to this upgrade, you feel compelled to support meTokens, which is completely self-funded, we welcome you to donate any legacy meTokens to our delegated address at donate.stakeonme.eth. We will burn only donated meTokens to unlock their underlying ETH from the old contracts to help recuperate our own costs. In total, we spent approximately 14.6 ETH on this upgrade and redeployment.

You can find your legacy meTokens by browsing etherscan, clicking the ‘tokens’ dropdown, and selecting any meToken with a “not active” symbol name. By adding the legacy address to your MetaMask wallet, you can then send legacy meTokens to our donate.stakeonme.eth address.

Lastly, we want to apologize for the radio silence during this last week. We’re still a small team with limited bandwidth, and we wanted to be completely heads down while we powered through this upgrade without any distractions. We originally were on schedule to complete everything within an initial 48hr window, but due to some unfortunate personal circumstances extended our upgrade through the weekend. Thank you kindly for your support and patience during the last week.

--

--

Chris Robison
meTokens

The affirmative of reduce friction is "Heighten Harmony." Let's build something together. #bitcoin #ethereum