-
Notifications
You must be signed in to change notification settings - Fork 0
EVM: Make settler upgradeable #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3070636
d0de369
e57a219
6b72533
5ac2cb7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can use this to compile npm files directly instead of doing this. You will need to upgrade hardhat to the latest version
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I couldn't make it work. It worked for deploying the contract, but failed when trying to verify it. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // SPDX-License-Identifier: GPL-3.0-or-later | ||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
|
|
||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
|
|
||
| // You should have received a copy of the GNU General Public License | ||
| // along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
|
||
| pragma solidity ^0.8.20; | ||
|
|
||
| import '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; | ||
|
|
||
| contract Proxy is TransparentUpgradeableProxy { | ||
| constructor(address implementation, address initialOwner, bytes memory data) | ||
| TransparentUpgradeableProxy(implementation, initialOwner, data) | ||
| {} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // SPDX-License-Identifier: GPL-3.0-or-later | ||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
|
|
||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
|
|
||
| // You should have received a copy of the GNU General Public License | ||
| // along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
|
||
| pragma solidity ^0.8.20; | ||
|
|
||
| import '../Settler.sol'; | ||
|
|
||
| contract SettlerV2Mock is Settler { | ||
| function someNewFunction() external pure returns (string memory) { | ||
| return 'Some new function'; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import { HardhatEthers, HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/types' | ||
| import { Contract, getAddress } from 'ethers' | ||
| import { network } from 'hardhat' | ||
|
|
||
| import ProxyAdminArtifact from '../artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json' | ||
| import SettlerArtifact from '../artifacts/contracts/Settler.sol/Settler.json' | ||
| import { deployCreate3 } from './deploy-create3' | ||
|
|
||
| const ERC1967_ADMIN_SLOT = '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103' | ||
|
|
||
| async function main(): Promise<void> { | ||
| const { ethers } = await network.connect() | ||
| const [signer] = await ethers.getSigners() | ||
|
|
||
| if (!process.env.SETTLER_PROXY) throw Error('SETTLER_PROXY env variable not provided') | ||
| const proxy = getAddress(process.env.SETTLER_PROXY) | ||
|
|
||
| const proxyAdmin = await getProxyAdmin(ethers, proxy, signer) | ||
| const proxyAdminOwner = await proxyAdmin.owner() | ||
| if (proxyAdminOwner !== signer.address) { | ||
| throw Error(`Signer ${signer.address} is not the ProxyAdmin owner ${proxyAdminOwner}`) | ||
| } | ||
|
|
||
| const implementation = await deployCreate3(SettlerArtifact, [], '0x1802') | ||
| const tx = await proxyAdmin.upgradeAndCall(proxy, implementation.target, '0x') | ||
| await tx.wait() | ||
| console.log(`✅ Settler ${proxy} upgraded in tx ${tx.hash}`) | ||
| } | ||
|
|
||
| async function getProxyAdmin(ethers: HardhatEthers, proxy: string, signer: HardhatEthersSigner): Promise<Contract> { | ||
| const rawAdmin = await ethers.provider.getStorage(proxy, ERC1967_ADMIN_SLOT) | ||
| const adminAddress = getAddress(`0x${rawAdmin.slice(-40)}`) | ||
| return ethers.getContractAt(ProxyAdminArtifact.abi, adminAddress, signer) | ||
| } | ||
|
|
||
| main().catch(console.error) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| import { HardhatEthers } from '@nomicfoundation/hardhat-ethers/types' | ||
| import { expect } from 'chai' | ||
| import { Contract, getAddress } from 'ethers' | ||
|
|
||
| /* eslint-disable no-secrets/no-secrets */ | ||
|
|
||
| const ERC1967_ADMIN_SLOT = '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103' | ||
|
|
||
| export default function itBehavesLikeUpgradeable(): void { | ||
| describe('initialize', () => { | ||
| it('locks the implementation initializer', async function () { | ||
| const implementation = await this.ethers.deployContract(this.implementationNameV1) | ||
|
|
||
| await expect(implementation.initialize(...this.initializeArgs)).to.be.revertedWithCustomError( | ||
| implementation, | ||
| 'InvalidInitialization' | ||
| ) | ||
| }) | ||
|
|
||
| it('cannot be initialized twice', async function () { | ||
| await expect(this.proxy.initialize(...this.initializeArgs)).to.be.revertedWithCustomError( | ||
| this.proxy, | ||
| 'InvalidInitialization' | ||
| ) | ||
| }) | ||
| }) | ||
|
|
||
| describe('upgradeAndCall', () => { | ||
| context('when the sender is the owner', () => { | ||
| it('upgrades the implementation', async function () { | ||
| const proxyAdmin = await getProxyAdmin(this.ethers, this.proxy) | ||
| const newImplementation = await this.ethers.deployContract(this.implementationNameV2) | ||
|
|
||
| await proxyAdmin.connect(this.proxyOwner).upgradeAndCall(this.proxy, newImplementation, '0x') | ||
| await this.assertUpgrade(this.proxy) | ||
| }) | ||
| }) | ||
|
|
||
| context('when the sender is not the owner', () => { | ||
| it('reverts', async function () { | ||
| const proxyAdmin = await getProxyAdmin(this.ethers, this.proxy) | ||
| const newImplementation = await this.ethers.deployContract(this.implementationNameV2) | ||
|
|
||
| await expect( | ||
| proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, newImplementation, '0x') | ||
| ).to.be.revertedWithCustomError(proxyAdmin, 'OwnableUnauthorizedAccount') | ||
| }) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| async function getProxyAdmin(ethers: HardhatEthers, proxy: Contract): Promise<Contract> { | ||
| const rawAdmin = await ethers.provider.getStorage(proxy.target as string, ERC1967_ADMIN_SLOT) | ||
| return new Contract( | ||
| getAddress(`0x${rawAdmin.slice(-40)}`), | ||
| [ | ||
| 'error OwnableUnauthorizedAccount(address account)', | ||
| 'function upgradeAndCall(address proxy, address implementation, bytes data) payable', | ||
| ], | ||
| ethers.provider | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to remove DynamicCallEncoder creation to avoid "contract size too big" error