Upgradeable snapps

Does the current/future implementation of snapps support upgradability? How does this impact the circuit/verification key generated and is backward compatibility maintained?

This was largely a pinch point in systems like Ethereum hence would love if some one from core could comment on this.

5 Likes

I totally agree with you that it is important to both upgrade and improve upon a snapp and fix potential vulnerabilities and bug when they arise. That is something that’s very important for both usability (making sure the contract keeps its address etc) and developer experience so that a developer can improve upon a product and fix potential vulnerabilities.

However, I also believe that there should be some sort of safety measure be included in the upgrading process when it comes to changing the source code of a snapp. I personally believe that even snapps should only be trusted by its code and not by the niceness of their developers, there should be a safety net in place to prevent deploying of malicious or allowing for easy “rug pulls”

1 Like

Given the commitment must change if the snapp does, upgrade means building in a path. An implementation that pauses all transactions except transfers to a new snapp version is a popular approach.

It is too trusting to allow developer-side upgrade ability at will. A “pause and upgrade” method, that also enables a back out to withdraw instead of upgrade, is the path I would suggest.

For snaps that are not handling important decisions or funds, a proxy approach may be appropriate as a simpler (for both users and developers) approach, where the proxy can route to the current version.

Standards for both exist that I would expect we will port to Mina.

1 Like

I guess a more creative approach unique to zk could be to have a test suite snapp and provide for automatic upgrades (via either of the other approaches I referenced) only if the test cases are proven to pass.

As a developer, I could migrate people to new versions on deploy, as long as my (unaltered) tests still pass. This approach could be interesting, but also puts a lot of trust in understanding the test suite and increases the attack surface. I don’t think I would recommend this approach, but it might be fun to explore anyway.

1 Like

Definition of Upgradability:

The ability to mutate the logic of a smart contract after it has been deployed.

Use Cases

  • Your contract uses Oracle A for some data, with the method signature #reveal(id: Uint64): Field, but you want to use a new provider, Oracle B, with a different signature #readData(merkleRoot: Field, pathPrefix?: Field): Field
  • Your contract contains a bug from an old version of the snarky js compiler

Proxy Design Pattern from Solidity

A common pattern in “upgradeable” contracts on ethereum is to use a master contract and dependent contracts that contain state and logic. See: Open Zeppelin.

Making a separate comment with my opinions. I think if we can trust a snapp developer to deploy arbitrary logic and execute it with whatever funds a contract stores, then we can also trust them to just deploy a new smart contract.

The idea of updating one smart contract over and over to keep the same address doesn’t seem to make as much sense if a snapp developer will be hosting the snapp themselves. Or even if they distribute their snapp as a release, they can just direct people to upgrade to the latest release. I think we will sort of need to see how snapps hosting shakes out once we have a live testnet, and even production environment, to fully understand what the upgradability needs are. But I suspect there will be better ways to handle the use cases, than the proxy design pattern. On Mina, nodes don’t all have to agree on the logic of the smart contract, they only have to agree on the state. So I don’t believe a developer will have to write a smart contact so abstractly as “here is some data and some mina, please do whatever it is that you do with it”. I don’t even think that maintaining the same address will be important, because a snapp will mostly (exclusively?) be accessed over the internet at a domain name. Like if uniswap.com upgraded its addresses in the background, but all the liquidity remained, most people wouldn’t even notice.

I think the better design pattern, though I don’t have the context to spec it out here, is just let a snapp dev redeploy their contract, change the address, move all the liquidity, and users won’t notice. It might sound dangerous to let a dev move your liquidity position on your behalf to a new contract, but note that this is exactly equivalent to an upgradeable contract. If anything, I would be interested in seeing if non upgradable contracts would be possible, where a dev would not be able to do this.

1 Like

According to the source code, the following permission can be set:

  /**
   * The [[ Perm ]] corresponding to the ability to set the snapp uri typically
   * pointing to the source code of the smart contract. Usually this should be
   * changed whenever the [[ Permissions.setVerificationKey ]] is changed.
   * Effectively "upgradability" of the smart contract.
   */
  setSnappUri: Perm;

So it seems like snapps will support directly resetting the contract logic via a configurable permissions system.

2 Likes

To expand on this, I’m reposting my answer on the same topic from discord:

I digged into it a bit, and it seems that our current design is really flexible (and IMO, good) regarding permissions.

For each snapp there is a list of capabilities , e.g.

  • Update the snapp state
  • Upgrade the snapp (verifier key)
  • Move funds out of the snapp
  • …

And for each of those, you can define on a per-snapp basis who has permissions to do them. AFAIU there are 2 kinds of permission:

  1. The snapp private key owner can do something
  2. A proof sent to the snapp can do something
    And you can combine them, like: Both of these have the capability, or: nobody has the capability.

Changing the permissions is itself another of those capabilities, which in the beginning resides at the private key owner. But he could change it and say: From now on, nobody can change the permissions and funds can only be sent out from a proof. Or: From now on, nobody can upgrade the snapp.

Importantly, all the permissions on a snapp are public and we hope that block explorers will display them.

Here you can see the relevant snarkyjs types and the defaults for all capabilities:

4 Likes

Thanks for sharing that with us, Gregor. I think this seems like a good and secure solution for upgrading snapps!