UUPSUpgradeable.test.js 3.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. const { expectEvent } = require('@openzeppelin/test-helpers');
  2. const { web3 } = require('@openzeppelin/test-helpers/src/setup');
  3. const { getSlot, ImplementationSlot } = require('../../helpers/erc1967');
  4. const { expectRevertCustomError } = require('../../helpers/customError');
  5. const ERC1967Proxy = artifacts.require('ERC1967Proxy');
  6. const UUPSUpgradeableMock = artifacts.require('UUPSUpgradeableMock');
  7. const UUPSUpgradeableUnsafeMock = artifacts.require('UUPSUpgradeableUnsafeMock');
  8. const UUPSUpgradeableLegacyMock = artifacts.require('UUPSUpgradeableLegacyMock');
  9. const NonUpgradeableMock = artifacts.require('NonUpgradeableMock');
  10. contract('UUPSUpgradeable', function () {
  11. before(async function () {
  12. this.implInitial = await UUPSUpgradeableMock.new();
  13. this.implUpgradeOk = await UUPSUpgradeableMock.new();
  14. this.implUpgradeUnsafe = await UUPSUpgradeableUnsafeMock.new();
  15. this.implUpgradeNonUUPS = await NonUpgradeableMock.new();
  16. });
  17. beforeEach(async function () {
  18. const { address } = await ERC1967Proxy.new(this.implInitial.address, '0x');
  19. this.instance = await UUPSUpgradeableMock.at(address);
  20. });
  21. it('upgrade to upgradeable implementation', async function () {
  22. const { receipt } = await this.instance.upgradeTo(this.implUpgradeOk.address);
  23. expect(receipt.logs.filter(({ event }) => event === 'Upgraded').length).to.be.equal(1);
  24. expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeOk.address });
  25. });
  26. it('upgrade to upgradeable implementation with call', async function () {
  27. expect(await this.instance.current()).to.be.bignumber.equal('0');
  28. const { receipt } = await this.instance.upgradeToAndCall(
  29. this.implUpgradeOk.address,
  30. this.implUpgradeOk.contract.methods.increment().encodeABI(),
  31. );
  32. expect(receipt.logs.filter(({ event }) => event === 'Upgraded').length).to.be.equal(1);
  33. expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeOk.address });
  34. expect(await this.instance.current()).to.be.bignumber.equal('1');
  35. });
  36. it('upgrade to and unsafe upgradeable implementation', async function () {
  37. const { receipt } = await this.instance.upgradeTo(this.implUpgradeUnsafe.address);
  38. expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeUnsafe.address });
  39. });
  40. // delegate to a non existing upgradeTo function causes a low level revert
  41. it('reject upgrade to non uups implementation', async function () {
  42. await expectRevertCustomError(
  43. this.instance.upgradeTo(this.implUpgradeNonUUPS.address),
  44. 'ERC1967InvalidImplementation',
  45. [this.implUpgradeNonUUPS.address],
  46. );
  47. });
  48. it('reject proxy address as implementation', async function () {
  49. const { address } = await ERC1967Proxy.new(this.implInitial.address, '0x');
  50. const otherInstance = await UUPSUpgradeableMock.at(address);
  51. await expectRevertCustomError(this.instance.upgradeTo(otherInstance.address), 'ERC1967InvalidImplementation', [
  52. otherInstance.address,
  53. ]);
  54. });
  55. it('can upgrade from legacy implementations', async function () {
  56. const legacyImpl = await UUPSUpgradeableLegacyMock.new();
  57. const legacyInstance = await ERC1967Proxy.new(legacyImpl.address, '0x').then(({ address }) =>
  58. UUPSUpgradeableLegacyMock.at(address),
  59. );
  60. const receipt = await legacyInstance.upgradeTo(this.implInitial.address);
  61. const UpgradedEvents = receipt.logs.filter(
  62. ({ address, event }) => address === legacyInstance.address && event === 'Upgraded',
  63. );
  64. expect(UpgradedEvents.length).to.be.equal(1);
  65. expectEvent(receipt, 'Upgraded', { implementation: this.implInitial.address });
  66. const implementationSlot = await getSlot(legacyInstance, ImplementationSlot);
  67. const implementationAddress = web3.utils.toChecksumAddress(implementationSlot.substr(-40));
  68. expect(implementationAddress).to.be.equal(this.implInitial.address);
  69. });
  70. });