UUPSUpgradeable.test.js 3.7 KB

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