Update docs
This commit is contained in:
@ -1,36 +1,34 @@
|
||||
const { expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { ethers } = require('hardhat');
|
||||
const { expect } = require('chai');
|
||||
const ImplV1 = artifacts.require('DummyImplementation');
|
||||
const ImplV2 = artifacts.require('DummyImplementationV2');
|
||||
const ProxyAdmin = artifacts.require('ProxyAdmin');
|
||||
const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy');
|
||||
const ITransparentUpgradeableProxy = artifacts.require('ITransparentUpgradeableProxy');
|
||||
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
|
||||
|
||||
const { getAddressInSlot, ImplementationSlot } = require('../../helpers/erc1967');
|
||||
const { expectRevertCustomError } = require('../../helpers/customError');
|
||||
const { computeCreateAddress } = require('../../helpers/create');
|
||||
const { getAddressInSlot, ImplementationSlot } = require('../../helpers/storage');
|
||||
|
||||
contract('ProxyAdmin', function (accounts) {
|
||||
const [proxyAdminOwner, anotherAccount] = accounts;
|
||||
async function fixture() {
|
||||
const [admin, other] = await ethers.getSigners();
|
||||
|
||||
before('set implementations', async function () {
|
||||
this.implementationV1 = await ImplV1.new();
|
||||
this.implementationV2 = await ImplV2.new();
|
||||
});
|
||||
const v1 = await ethers.deployContract('DummyImplementation');
|
||||
const v2 = await ethers.deployContract('DummyImplementationV2');
|
||||
|
||||
const proxy = await ethers
|
||||
.deployContract('TransparentUpgradeableProxy', [v1, admin, '0x'])
|
||||
.then(instance => ethers.getContractAt('ITransparentUpgradeableProxy', instance));
|
||||
|
||||
const proxyAdmin = await ethers.getContractAt(
|
||||
'ProxyAdmin',
|
||||
ethers.getCreateAddress({ from: proxy.target, nonce: 1n }),
|
||||
);
|
||||
|
||||
return { admin, other, v1, v2, proxy, proxyAdmin };
|
||||
}
|
||||
|
||||
describe('ProxyAdmin', function () {
|
||||
beforeEach(async function () {
|
||||
const initializeData = Buffer.from('');
|
||||
const proxy = await TransparentUpgradeableProxy.new(this.implementationV1.address, proxyAdminOwner, initializeData);
|
||||
|
||||
const proxyNonce = await web3.eth.getTransactionCount(proxy.address);
|
||||
const proxyAdminAddress = computeCreateAddress(proxy.address, proxyNonce - 1); // Nonce already used
|
||||
this.proxyAdmin = await ProxyAdmin.at(proxyAdminAddress);
|
||||
|
||||
this.proxy = await ITransparentUpgradeableProxy.at(proxy.address);
|
||||
Object.assign(this, await loadFixture(fixture));
|
||||
});
|
||||
|
||||
it('has an owner', async function () {
|
||||
expect(await this.proxyAdmin.owner()).to.equal(proxyAdminOwner);
|
||||
expect(await this.proxyAdmin.owner()).to.equal(this.admin);
|
||||
});
|
||||
|
||||
it('has an interface version', async function () {
|
||||
@ -38,64 +36,45 @@ contract('ProxyAdmin', function (accounts) {
|
||||
});
|
||||
|
||||
describe('without data', function () {
|
||||
context('with unauthorized account', function () {
|
||||
describe('with unauthorized account', function () {
|
||||
it('fails to upgrade', async function () {
|
||||
await expectRevertCustomError(
|
||||
this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, '0x', {
|
||||
from: anotherAccount,
|
||||
}),
|
||||
'OwnableUnauthorizedAccount',
|
||||
[anotherAccount],
|
||||
);
|
||||
await expect(this.proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, this.v2, '0x'))
|
||||
.to.be.revertedWithCustomError(this.proxyAdmin, 'OwnableUnauthorizedAccount')
|
||||
.withArgs(this.other);
|
||||
});
|
||||
});
|
||||
|
||||
context('with authorized account', function () {
|
||||
describe('with authorized account', function () {
|
||||
it('upgrades implementation', async function () {
|
||||
await this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, '0x', {
|
||||
from: proxyAdminOwner,
|
||||
});
|
||||
|
||||
const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot);
|
||||
expect(implementationAddress).to.be.equal(this.implementationV2.address);
|
||||
await this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, '0x');
|
||||
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.v2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with data', function () {
|
||||
context('with unauthorized account', function () {
|
||||
describe('with unauthorized account', function () {
|
||||
it('fails to upgrade', async function () {
|
||||
const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI();
|
||||
await expectRevertCustomError(
|
||||
this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, {
|
||||
from: anotherAccount,
|
||||
}),
|
||||
'OwnableUnauthorizedAccount',
|
||||
[anotherAccount],
|
||||
);
|
||||
const data = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [1337n]);
|
||||
await expect(this.proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, this.v2, data))
|
||||
.to.be.revertedWithCustomError(this.proxyAdmin, 'OwnableUnauthorizedAccount')
|
||||
.withArgs(this.other);
|
||||
});
|
||||
});
|
||||
|
||||
context('with authorized account', function () {
|
||||
context('with invalid callData', function () {
|
||||
describe('with authorized account', function () {
|
||||
describe('with invalid callData', function () {
|
||||
it('fails to upgrade', async function () {
|
||||
const callData = '0x12345678';
|
||||
await expectRevert.unspecified(
|
||||
this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, {
|
||||
from: proxyAdminOwner,
|
||||
}),
|
||||
);
|
||||
const data = '0x12345678';
|
||||
await expect(this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, data)).to.be.reverted;
|
||||
});
|
||||
});
|
||||
|
||||
context('with valid callData', function () {
|
||||
describe('with valid callData', function () {
|
||||
it('upgrades implementation', async function () {
|
||||
const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI();
|
||||
await this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, {
|
||||
from: proxyAdminOwner,
|
||||
});
|
||||
const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot);
|
||||
expect(implementationAddress).to.be.equal(this.implementationV2.address);
|
||||
const data = this.v2.interface.encodeFunctionData('initializeNonPayableWithValue', [1337n]);
|
||||
await this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, data);
|
||||
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.v2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user