OpenZeppelin Upgrades Plugins for Buidler and Truffle

We are releasing two new packages to deploy and manage upgradeable contracts from Nomic Labs’ buidler and Truffle! With them, you can easily and securely leverage the full flexibility of contract upgrades directly from your Buidler scripts or Truffle migrations.

https://github.com/OpenZeppelin/openzeppelin-upgrades


We have been working on secure proxy-based upgrades for several years already, from early experiments in OpenZeppelin Labs, to the more recent OpenZeppelin CLI and OpenZeppelin Upgrades library. The library includes the proxy pattern implementations and TypeScript wrappers around them, while the CLI manages their deployment and upgrades as well other tasks related to a contracts toolchain like compilation or verification.

However, we noted that several users approached the library to make use of the proxy contracts only, and integrate them into their existing toolchains, usually powered by either Buidler or Truffle. This required some manual work to put together, and was potentially insecure since it didn’t include validations to ensure the upgrades were safe.

To cater for this increasing number of users, and in collaboration with the Nomic and Truffle teams, we decided to ship first-class integration of the upgrades proxy pattern for Buidler and Truffle with two new packages.

These plugins add new deployProxy and upgradeProxy functions in Buidler external scripts, Truffle migrations (support for Truffle external scripts is coming soon), and in the test environments of both frameworks. The Buidler plugin builds heavily upon ethers.js, while the Truffle one uses Truffle Contracts and web3.js.

const { ethers, upgrades } = require("@nomiclabs/buidler");

async function main() {
  const Box = await ethers.getContractFactory("Box");
  const instance = await upgrades.deployProxy(Box, [42]);
  await instance.deployed();

  const BoxV2 = await ethers.getContractFactory("BoxV2");
  const upgraded = await upgrades.upgradeProxy(instance.address, BoxV2);
  await upgraded.deployed();
}

main();
const { deployProxy, upgradeProxy } = require('@openzeppelin/truffle-upgrades');

const Box = artifacts.require('Box');
const BoxV2 = artifacts.require('BoxV2');

module.exports = async function (deployer) {
  const instance = await deployProxy(Box, [42], { deployer });
  const upgraded = await upgradeProxy(instance.address, BoxV2, { deployer });
}

 

The plugins rely on the same proxy contracts as the OpenZeppelin Upgrades library (and hence the CLI), so you don’t have to change anything on-chain if you want to migrate your current upgradeable project to the Buidler or Truffle plugin.

Both plugins will keep track of the deployed implementation contracts in a local .openzeppelin folder in the root directory of your project, similar to the existing OpenZeppelin CLI. However, note that the format used by the plugins for storing deployment info is not compatible with that of the CLI – though we are working on a simple migration path for users interested in it.

The plugins are backed by a brand-new typescript library for managing upgrades. The current OpenZeppelin Upgrades library was originally built to power the CLI, and was tightly integrated with several ZeppelinOS concepts which are now deprecated. This rewrite yielded a much cleaner library, one that integrates much easily with existing toolchains.

Last but not least, the plugins also provide methods for transferring upgrade rights of your proxies to another address. This allows you to use a regular wallet for quick iterations during development, and switch to a more secure option such as OpenZeppelin Upgrades App for Gnosis Safe as you go into production.


These plugins are a new effort to make upgrades as easy to use and as secure as possible for all Ethereum developers, by making them available to users of the most popular developer toolchains. Please let us know in the community forum what you think, and how we can make them easier to use for you!