ProxyAdmin.test.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. const { expectRevert } = require('@openzeppelin/test-helpers');
  2. const { expect } = require('chai');
  3. const ImplV1 = artifacts.require('DummyImplementation');
  4. const ImplV2 = artifacts.require('DummyImplementationV2');
  5. const ProxyAdmin = artifacts.require('ProxyAdmin');
  6. const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy');
  7. const ITransparentUpgradeableProxy = artifacts.require('ITransparentUpgradeableProxy');
  8. const { getAddressInSlot, ImplementationSlot, AdminSlot } = require('../../helpers/erc1967');
  9. const { expectRevertCustomError } = require('../../helpers/customError');
  10. contract('ProxyAdmin', function (accounts) {
  11. const [proxyAdminOwner, newAdmin, anotherAccount] = accounts;
  12. before('set implementations', async function () {
  13. this.implementationV1 = await ImplV1.new();
  14. this.implementationV2 = await ImplV2.new();
  15. });
  16. beforeEach(async function () {
  17. const initializeData = Buffer.from('');
  18. this.proxyAdmin = await ProxyAdmin.new(proxyAdminOwner);
  19. const proxy = await TransparentUpgradeableProxy.new(
  20. this.implementationV1.address,
  21. this.proxyAdmin.address,
  22. initializeData,
  23. );
  24. this.proxy = await ITransparentUpgradeableProxy.at(proxy.address);
  25. });
  26. it('has an owner', async function () {
  27. expect(await this.proxyAdmin.owner()).to.equal(proxyAdminOwner);
  28. });
  29. describe('#changeProxyAdmin', function () {
  30. it('fails to change proxy admin if its not the proxy owner', async function () {
  31. await expectRevertCustomError(
  32. this.proxyAdmin.changeProxyAdmin(this.proxy.address, newAdmin, { from: anotherAccount }),
  33. 'OwnableUnauthorizedAccount',
  34. [anotherAccount],
  35. );
  36. });
  37. it('changes proxy admin', async function () {
  38. await this.proxyAdmin.changeProxyAdmin(this.proxy.address, newAdmin, { from: proxyAdminOwner });
  39. const newProxyAdmin = await getAddressInSlot(this.proxy, AdminSlot);
  40. expect(newProxyAdmin).to.be.equal(newAdmin);
  41. });
  42. });
  43. describe('#upgrade', function () {
  44. context('with unauthorized account', function () {
  45. it('fails to upgrade', async function () {
  46. await expectRevertCustomError(
  47. this.proxyAdmin.upgrade(this.proxy.address, this.implementationV2.address, { from: anotherAccount }),
  48. 'OwnableUnauthorizedAccount',
  49. [anotherAccount],
  50. );
  51. });
  52. });
  53. context('with authorized account', function () {
  54. it('upgrades implementation', async function () {
  55. await this.proxyAdmin.upgrade(this.proxy.address, this.implementationV2.address, { from: proxyAdminOwner });
  56. const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot);
  57. expect(implementationAddress).to.be.equal(this.implementationV2.address);
  58. });
  59. });
  60. });
  61. describe('#upgradeAndCall', function () {
  62. context('with unauthorized account', function () {
  63. it('fails to upgrade', async function () {
  64. const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI();
  65. await expectRevertCustomError(
  66. this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, {
  67. from: anotherAccount,
  68. }),
  69. 'OwnableUnauthorizedAccount',
  70. [anotherAccount],
  71. );
  72. });
  73. });
  74. context('with authorized account', function () {
  75. context('with invalid callData', function () {
  76. it('fails to upgrade', async function () {
  77. const callData = '0x12345678';
  78. await expectRevert.unspecified(
  79. this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, {
  80. from: proxyAdminOwner,
  81. }),
  82. );
  83. });
  84. });
  85. context('with valid callData', function () {
  86. it('upgrades implementation', async function () {
  87. const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI();
  88. await this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, {
  89. from: proxyAdminOwner,
  90. });
  91. const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot);
  92. expect(implementationAddress).to.be.equal(this.implementationV2.address);
  93. });
  94. });
  95. });
  96. });
  97. });