ProxyAdmin.test.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. const { ethers } = require('hardhat');
  2. const { expect } = require('chai');
  3. const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
  4. const { getAddressInSlot, ImplementationSlot } = require('../../helpers/storage');
  5. async function fixture() {
  6. const [admin, other] = await ethers.getSigners();
  7. const v1 = await ethers.deployContract('DummyImplementation');
  8. const v2 = await ethers.deployContract('DummyImplementationV2');
  9. const proxy = await ethers
  10. .deployContract('TransparentUpgradeableProxy', [v1, admin, '0x'])
  11. .then(instance => ethers.getContractAt('ITransparentUpgradeableProxy', instance));
  12. const proxyAdmin = await ethers.getContractAt(
  13. 'ProxyAdmin',
  14. ethers.getCreateAddress({ from: proxy.target, nonce: 1n }),
  15. );
  16. return { admin, other, v1, v2, proxy, proxyAdmin };
  17. }
  18. describe('ProxyAdmin', function () {
  19. beforeEach(async function () {
  20. Object.assign(this, await loadFixture(fixture));
  21. });
  22. it('has an owner', async function () {
  23. expect(await this.proxyAdmin.owner()).to.equal(this.admin);
  24. });
  25. it('has an interface version', async function () {
  26. expect(await this.proxyAdmin.UPGRADE_INTERFACE_VERSION()).to.equal('5.0.0');
  27. });
  28. describe('without data', function () {
  29. context('with unauthorized account', function () {
  30. it('fails to upgrade', async function () {
  31. await expect(this.proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, this.v2, '0x'))
  32. .to.be.revertedWithCustomError(this.proxyAdmin, 'OwnableUnauthorizedAccount')
  33. .withArgs(this.other);
  34. });
  35. });
  36. context('with authorized account', function () {
  37. it('upgrades implementation', async function () {
  38. await this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, '0x');
  39. expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.be.equal(this.v2);
  40. });
  41. });
  42. });
  43. describe('with data', function () {
  44. context('with unauthorized account', function () {
  45. it('fails to upgrade', async function () {
  46. const data = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [1337n]);
  47. await expect(this.proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, this.v2, data))
  48. .to.be.revertedWithCustomError(this.proxyAdmin, 'OwnableUnauthorizedAccount')
  49. .withArgs(this.other);
  50. });
  51. });
  52. context('with authorized account', function () {
  53. context('with invalid callData', function () {
  54. it('fails to upgrade', async function () {
  55. const data = '0x12345678';
  56. await expect(this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, data)).to.be.reverted;
  57. });
  58. });
  59. context('with valid callData', function () {
  60. it('upgrades implementation', async function () {
  61. const data = this.v2.interface.encodeFunctionData('initializeNonPayableWithValue', [1337n]);
  62. await this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, data);
  63. expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.be.equal(this.v2);
  64. });
  65. });
  66. });
  67. });
  68. });