From 98f19039b69f92ec80433bc297e7e4ed2a868db6 Mon Sep 17 00:00:00 2001 From: Nick Barry Date: Thu, 12 Oct 2023 14:36:32 -0400 Subject: [PATCH 01/10] rename ManagedProxy to BeaconProxy --- abi/{IManagedProxy.json => BeaconProxy.json} | 2 +- ...xyOwnable.json => BeaconProxyOwnable.json} | 2 +- ...gedProxyOwnable.json => IBeaconProxy.json} | 2 +- ...gedProxy.json => IBeaconProxyOwnable.json} | 2 +- contracts/proxy/beacon/BeaconProxy.sol | 38 +++++++++++++++++++ contracts/proxy/beacon/BeaconProxyMock.sol | 33 ++++++++++++++++ contracts/proxy/beacon/BeaconProxyOwnable.sol | 23 +++++++++++ .../BeaconProxyOwnableMock.sol} | 16 ++++---- .../IBeaconProxy.sol} | 4 +- .../proxy/beacon/IBeaconProxyOwnable.sol | 7 ++++ .../proxy/managed/IManagedProxyOwnable.sol | 7 ---- contracts/proxy/managed/ManagedProxy.sol | 38 ------------------- contracts/proxy/managed/ManagedProxyMock.sol | 33 ---------------- .../proxy/managed/ManagedProxyOwnable.sol | 23 ----------- .../BeaconProxy.behavior.ts} | 12 +++--- .../beacon/BeaconProxyOwnable.behavior.ts | 31 +++++++++++++++ spec/proxy/beacon/index.ts | 2 + spec/proxy/index.ts | 2 +- .../managed/ManagedProxyOwnable.behavior.ts | 31 --------------- spec/proxy/managed/index.ts | 2 - .../ManagedProxy.ts => beacon/BeaconProxy.ts} | 32 ++++++++-------- .../BeaconProxyOwnable.ts} | 34 ++++++++--------- 22 files changed, 188 insertions(+), 188 deletions(-) rename abi/{IManagedProxy.json => BeaconProxy.json} (79%) rename abi/{ManagedProxyOwnable.json => BeaconProxyOwnable.json} (93%) rename abi/{IManagedProxyOwnable.json => IBeaconProxy.json} (79%) rename abi/{ManagedProxy.json => IBeaconProxyOwnable.json} (79%) create mode 100644 contracts/proxy/beacon/BeaconProxy.sol create mode 100644 contracts/proxy/beacon/BeaconProxyMock.sol create mode 100644 contracts/proxy/beacon/BeaconProxyOwnable.sol rename contracts/proxy/{managed/ManagedProxyOwnableMock.sol => beacon/BeaconProxyOwnableMock.sol} (55%) rename contracts/proxy/{managed/IManagedProxy.sol => beacon/IBeaconProxy.sol} (53%) create mode 100644 contracts/proxy/beacon/IBeaconProxyOwnable.sol delete mode 100644 contracts/proxy/managed/IManagedProxyOwnable.sol delete mode 100644 contracts/proxy/managed/ManagedProxy.sol delete mode 100644 contracts/proxy/managed/ManagedProxyMock.sol delete mode 100644 contracts/proxy/managed/ManagedProxyOwnable.sol rename spec/proxy/{managed/ManagedProxy.behavior.ts => beacon/BeaconProxy.behavior.ts} (59%) create mode 100644 spec/proxy/beacon/BeaconProxyOwnable.behavior.ts create mode 100644 spec/proxy/beacon/index.ts delete mode 100644 spec/proxy/managed/ManagedProxyOwnable.behavior.ts delete mode 100644 spec/proxy/managed/index.ts rename test/proxy/{managed/ManagedProxy.ts => beacon/BeaconProxy.ts} (63%) rename test/proxy/{managed/ManagedProxyOwnable.ts => beacon/BeaconProxyOwnable.ts} (61%) diff --git a/abi/IManagedProxy.json b/abi/BeaconProxy.json similarity index 79% rename from abi/IManagedProxy.json rename to abi/BeaconProxy.json index a412d93f..cc399d94 100644 --- a/abi/IManagedProxy.json +++ b/abi/BeaconProxy.json @@ -1,7 +1,7 @@ [ { "inputs": [], - "name": "ManagedProxy__FetchImplementationFailed", + "name": "BeaconProxy__FetchImplementationFailed", "type": "error" }, { diff --git a/abi/ManagedProxyOwnable.json b/abi/BeaconProxyOwnable.json similarity index 93% rename from abi/ManagedProxyOwnable.json rename to abi/BeaconProxyOwnable.json index fcf0038e..4398641d 100644 --- a/abi/ManagedProxyOwnable.json +++ b/abi/BeaconProxyOwnable.json @@ -1,7 +1,7 @@ [ { "inputs": [], - "name": "ManagedProxy__FetchImplementationFailed", + "name": "BeaconProxy__FetchImplementationFailed", "type": "error" }, { diff --git a/abi/IManagedProxyOwnable.json b/abi/IBeaconProxy.json similarity index 79% rename from abi/IManagedProxyOwnable.json rename to abi/IBeaconProxy.json index a412d93f..cc399d94 100644 --- a/abi/IManagedProxyOwnable.json +++ b/abi/IBeaconProxy.json @@ -1,7 +1,7 @@ [ { "inputs": [], - "name": "ManagedProxy__FetchImplementationFailed", + "name": "BeaconProxy__FetchImplementationFailed", "type": "error" }, { diff --git a/abi/ManagedProxy.json b/abi/IBeaconProxyOwnable.json similarity index 79% rename from abi/ManagedProxy.json rename to abi/IBeaconProxyOwnable.json index a412d93f..cc399d94 100644 --- a/abi/ManagedProxy.json +++ b/abi/IBeaconProxyOwnable.json @@ -1,7 +1,7 @@ [ { "inputs": [], - "name": "ManagedProxy__FetchImplementationFailed", + "name": "BeaconProxy__FetchImplementationFailed", "type": "error" }, { diff --git a/contracts/proxy/beacon/BeaconProxy.sol b/contracts/proxy/beacon/BeaconProxy.sol new file mode 100644 index 00000000..995f7885 --- /dev/null +++ b/contracts/proxy/beacon/BeaconProxy.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.8; + +import { Proxy } from '../Proxy.sol'; +import { IBeaconProxy } from './IBeaconProxy.sol'; + +/** + * @title Proxy with externally controlled implementation + * @dev implementation fetched using immutable function selector + */ +abstract contract BeaconProxy is IBeaconProxy, Proxy { + bytes4 internal immutable FETCH_IMPLEMENTATION_SELECTOR; + + /** + * @param fetchImplementationSelector function selector used to fetch implementation from beacon + */ + constructor(bytes4 fetchImplementationSelector) { + FETCH_IMPLEMENTATION_SELECTOR = fetchImplementationSelector; + } + + /** + * @inheritdoc Proxy + */ + function _getImplementation() internal view override returns (address) { + (bool success, bytes memory data) = _getBeacon().staticcall( + abi.encodePacked(FETCH_IMPLEMENTATION_SELECTOR) + ); + if (!success) revert BeaconProxy__FetchImplementationFailed(); + return abi.decode(data, (address)); + } + + /** + * @notice get beacon of proxy implementation + * @return beacon address + */ + function _getBeacon() internal view virtual returns (address); +} diff --git a/contracts/proxy/beacon/BeaconProxyMock.sol b/contracts/proxy/beacon/BeaconProxyMock.sol new file mode 100644 index 00000000..da063433 --- /dev/null +++ b/contracts/proxy/beacon/BeaconProxyMock.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.8; + +import { BeaconProxy } from './BeaconProxy.sol'; + +contract BeaconProxyMock is BeaconProxy { + address private _beacon; + + constructor( + address beacon, + bytes4 fetchImplementationSelector + ) BeaconProxy(fetchImplementationSelector) { + setBeacon(beacon); + } + + function _getBeacon() internal view override returns (address) { + return _beacon; + } + + function __getImplementation() external view returns (address) { + return _getImplementation(); + } + + function setBeacon(address beacon) public { + _beacon = beacon; + } + + /** + * @dev suppress compiler warning + */ + receive() external payable {} +} diff --git a/contracts/proxy/beacon/BeaconProxyOwnable.sol b/contracts/proxy/beacon/BeaconProxyOwnable.sol new file mode 100644 index 00000000..5a8a4754 --- /dev/null +++ b/contracts/proxy/beacon/BeaconProxyOwnable.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.8; + +import { OwnableInternal } from '../../access/ownable/OwnableInternal.sol'; +import { IBeaconProxyOwnable } from './IBeaconProxyOwnable.sol'; +import { BeaconProxy } from './BeaconProxy.sol'; + +/** + * @title Proxy with implementation controlled by ERC171 owner + */ +abstract contract BeaconProxyOwnable is + IBeaconProxyOwnable, + BeaconProxy, + OwnableInternal +{ + /** + * @inheritdoc BeaconProxy + */ + function _getBeacon() internal view override returns (address) { + return _owner(); + } +} diff --git a/contracts/proxy/managed/ManagedProxyOwnableMock.sol b/contracts/proxy/beacon/BeaconProxyOwnableMock.sol similarity index 55% rename from contracts/proxy/managed/ManagedProxyOwnableMock.sol rename to contracts/proxy/beacon/BeaconProxyOwnableMock.sol index 69ad221a..10dca021 100644 --- a/contracts/proxy/managed/ManagedProxyOwnableMock.sol +++ b/contracts/proxy/beacon/BeaconProxyOwnableMock.sol @@ -2,22 +2,22 @@ pragma solidity ^0.8.8; -import { ManagedProxy, ManagedProxyOwnable } from './ManagedProxyOwnable.sol'; +import { BeaconProxy, BeaconProxyOwnable } from './BeaconProxyOwnable.sol'; -contract ManagedProxyOwnableMock is ManagedProxyOwnable { +contract BeaconProxyOwnableMock is BeaconProxyOwnable { constructor( - address manager, - bytes4 managerSelector - ) ManagedProxy(managerSelector) { - setOwner(manager); + address beacon, + bytes4 fetchImplementationSelector + ) BeaconProxy(fetchImplementationSelector) { + setOwner(beacon); } function __getImplementation() external view returns (address) { return _getImplementation(); } - function __getManager() external view returns (address) { - return _getManager(); + function __getBeacon() external view returns (address) { + return _getBeacon(); } function getOwner() external view returns (address) { diff --git a/contracts/proxy/managed/IManagedProxy.sol b/contracts/proxy/beacon/IBeaconProxy.sol similarity index 53% rename from contracts/proxy/managed/IManagedProxy.sol rename to contracts/proxy/beacon/IBeaconProxy.sol index db85bced..702cc8ed 100644 --- a/contracts/proxy/managed/IManagedProxy.sol +++ b/contracts/proxy/beacon/IBeaconProxy.sol @@ -4,6 +4,6 @@ pragma solidity ^0.8.8; import { IProxy } from '../IProxy.sol'; -interface IManagedProxy is IProxy { - error ManagedProxy__FetchImplementationFailed(); +interface IBeaconProxy is IProxy { + error BeaconProxy__FetchImplementationFailed(); } diff --git a/contracts/proxy/beacon/IBeaconProxyOwnable.sol b/contracts/proxy/beacon/IBeaconProxyOwnable.sol new file mode 100644 index 00000000..989bdd4f --- /dev/null +++ b/contracts/proxy/beacon/IBeaconProxyOwnable.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.8; + +import { IBeaconProxy } from './IBeaconProxy.sol'; + +interface IBeaconProxyOwnable is IBeaconProxy {} diff --git a/contracts/proxy/managed/IManagedProxyOwnable.sol b/contracts/proxy/managed/IManagedProxyOwnable.sol deleted file mode 100644 index 5a5ced91..00000000 --- a/contracts/proxy/managed/IManagedProxyOwnable.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.8; - -import { IManagedProxy } from './IManagedProxy.sol'; - -interface IManagedProxyOwnable is IManagedProxy {} diff --git a/contracts/proxy/managed/ManagedProxy.sol b/contracts/proxy/managed/ManagedProxy.sol deleted file mode 100644 index ff2d490b..00000000 --- a/contracts/proxy/managed/ManagedProxy.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.8; - -import { Proxy } from '../Proxy.sol'; -import { IManagedProxy } from './IManagedProxy.sol'; - -/** - * @title Proxy with externally controlled implementation - * @dev implementation fetched using immutable function selector - */ -abstract contract ManagedProxy is IManagedProxy, Proxy { - bytes4 internal immutable MANAGER_SELECTOR; - - /** - * @param managerSelector function selector used to fetch implementation from manager - */ - constructor(bytes4 managerSelector) { - MANAGER_SELECTOR = managerSelector; - } - - /** - * @inheritdoc Proxy - */ - function _getImplementation() internal view override returns (address) { - (bool success, bytes memory data) = _getManager().staticcall( - abi.encodePacked(MANAGER_SELECTOR) - ); - if (!success) revert ManagedProxy__FetchImplementationFailed(); - return abi.decode(data, (address)); - } - - /** - * @notice get manager of proxy implementation - * @return manager address - */ - function _getManager() internal view virtual returns (address); -} diff --git a/contracts/proxy/managed/ManagedProxyMock.sol b/contracts/proxy/managed/ManagedProxyMock.sol deleted file mode 100644 index c1762af6..00000000 --- a/contracts/proxy/managed/ManagedProxyMock.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.8; - -import { ManagedProxy } from './ManagedProxy.sol'; - -contract ManagedProxyMock is ManagedProxy { - address private _manager; - - constructor( - address manager, - bytes4 managerSelector - ) ManagedProxy(managerSelector) { - setManager(manager); - } - - function _getManager() internal view override returns (address) { - return _manager; - } - - function __getImplementation() external view returns (address) { - return _getImplementation(); - } - - function setManager(address manager) public { - _manager = manager; - } - - /** - * @dev suppress compiler warning - */ - receive() external payable {} -} diff --git a/contracts/proxy/managed/ManagedProxyOwnable.sol b/contracts/proxy/managed/ManagedProxyOwnable.sol deleted file mode 100644 index dbc90e39..00000000 --- a/contracts/proxy/managed/ManagedProxyOwnable.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.8; - -import { OwnableInternal } from '../../access/ownable/OwnableInternal.sol'; -import { IManagedProxyOwnable } from './IManagedProxyOwnable.sol'; -import { ManagedProxy } from './ManagedProxy.sol'; - -/** - * @title Proxy with implementation controlled by ERC171 owner - */ -abstract contract ManagedProxyOwnable is - IManagedProxyOwnable, - ManagedProxy, - OwnableInternal -{ - /** - * @inheritdoc ManagedProxy - */ - function _getManager() internal view override returns (address) { - return _owner(); - } -} diff --git a/spec/proxy/managed/ManagedProxy.behavior.ts b/spec/proxy/beacon/BeaconProxy.behavior.ts similarity index 59% rename from spec/proxy/managed/ManagedProxy.behavior.ts rename to spec/proxy/beacon/BeaconProxy.behavior.ts index 05d18177..19833232 100644 --- a/spec/proxy/managed/ManagedProxy.behavior.ts +++ b/spec/proxy/beacon/BeaconProxy.behavior.ts @@ -1,20 +1,20 @@ import { describeBehaviorOfProxy, ProxyBehaviorArgs } from '../Proxy.behavior'; import { describeFilter } from '@solidstate/library'; -import { IManagedProxy } from '@solidstate/typechain-types'; +import { IBeaconProxy } from '@solidstate/typechain-types'; -export interface ManagedProxyBehaviorArgs extends ProxyBehaviorArgs {} +export interface BeaconProxyBehaviorArgs extends ProxyBehaviorArgs {} -export function describeBehaviorOfManagedProxy( - deploy: () => Promise, +export function describeBehaviorOfBeaconProxy( + deploy: () => Promise, { implementationFunction, implementationFunctionArgs, - }: ManagedProxyBehaviorArgs, + }: BeaconProxyBehaviorArgs, skips?: string[], ) { const describe = describeFilter(skips); - describe('::ManagedProxy', () => { + describe('::BeaconProxy', () => { describeBehaviorOfProxy( deploy, { diff --git a/spec/proxy/beacon/BeaconProxyOwnable.behavior.ts b/spec/proxy/beacon/BeaconProxyOwnable.behavior.ts new file mode 100644 index 00000000..40943e81 --- /dev/null +++ b/spec/proxy/beacon/BeaconProxyOwnable.behavior.ts @@ -0,0 +1,31 @@ +import { + describeBehaviorOfBeaconProxy, + BeaconProxyBehaviorArgs, +} from './BeaconProxy.behavior'; +import { describeFilter } from '@solidstate/library'; +import { IBeaconProxyOwnable } from '@solidstate/typechain-types'; + +export interface BeaconProxyOwnableBehaviorArgs + extends BeaconProxyBehaviorArgs {} + +export function describeBehaviorOfBeaconProxyOwnable( + deploy: () => Promise, + { + implementationFunction, + implementationFunctionArgs, + }: BeaconProxyOwnableBehaviorArgs, + skips?: string[], +) { + const describe = describeFilter(skips); + + describe('::BeaconProxyOwnable', () => { + describeBehaviorOfBeaconProxy( + deploy, + { + implementationFunction, + implementationFunctionArgs, + }, + [], + ); + }); +} diff --git a/spec/proxy/beacon/index.ts b/spec/proxy/beacon/index.ts new file mode 100644 index 00000000..7aa3942c --- /dev/null +++ b/spec/proxy/beacon/index.ts @@ -0,0 +1,2 @@ +export * from './BeaconProxy.behavior'; +export * from './BeaconProxyOwnable.behavior'; diff --git a/spec/proxy/index.ts b/spec/proxy/index.ts index 22e6a8b9..5d8128ab 100644 --- a/spec/proxy/index.ts +++ b/spec/proxy/index.ts @@ -1,5 +1,5 @@ export * from './diamond'; -export * from './managed'; +export * from './beacon'; export * from './upgradeable'; export * from './Proxy.behavior'; diff --git a/spec/proxy/managed/ManagedProxyOwnable.behavior.ts b/spec/proxy/managed/ManagedProxyOwnable.behavior.ts deleted file mode 100644 index ef1ae7b9..00000000 --- a/spec/proxy/managed/ManagedProxyOwnable.behavior.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - describeBehaviorOfManagedProxy, - ManagedProxyBehaviorArgs, -} from './ManagedProxy.behavior'; -import { describeFilter } from '@solidstate/library'; -import { IManagedProxyOwnable } from '@solidstate/typechain-types'; - -export interface ManagedProxyOwnableBehaviorArgs - extends ManagedProxyBehaviorArgs {} - -export function describeBehaviorOfManagedProxyOwnable( - deploy: () => Promise, - { - implementationFunction, - implementationFunctionArgs, - }: ManagedProxyOwnableBehaviorArgs, - skips?: string[], -) { - const describe = describeFilter(skips); - - describe('::ManagedProxyOwnable', () => { - describeBehaviorOfManagedProxy( - deploy, - { - implementationFunction, - implementationFunctionArgs, - }, - [], - ); - }); -} diff --git a/spec/proxy/managed/index.ts b/spec/proxy/managed/index.ts deleted file mode 100644 index c7d0c534..00000000 --- a/spec/proxy/managed/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './ManagedProxy.behavior'; -export * from './ManagedProxyOwnable.behavior'; diff --git a/test/proxy/managed/ManagedProxy.ts b/test/proxy/beacon/BeaconProxy.ts similarity index 63% rename from test/proxy/managed/ManagedProxy.ts rename to test/proxy/beacon/BeaconProxy.ts index 60f5dde4..7543c9b1 100644 --- a/test/proxy/managed/ManagedProxy.ts +++ b/test/proxy/beacon/BeaconProxy.ts @@ -1,16 +1,16 @@ import { deployMockContract } from '@solidstate/library'; -import { describeBehaviorOfManagedProxy } from '@solidstate/spec'; +import { describeBehaviorOfBeaconProxy } from '@solidstate/spec'; import { - ManagedProxyMock, - ManagedProxyMock__factory, + BeaconProxyMock, + BeaconProxyMock__factory, OwnableMock__factory, } from '@solidstate/typechain-types'; import { expect } from 'chai'; import { ethers } from 'hardhat'; -describe('ManagedProxy', () => { - let manager: any; - let instance: ManagedProxyMock; +describe('BeaconProxy', () => { + let beacon: any; + let instance: BeaconProxyMock; beforeEach(async () => { const [deployer] = await ethers.getSigners(); @@ -19,11 +19,11 @@ describe('ManagedProxy', () => { deployer, ).deploy(ethers.ZeroAddress); - manager = await deployMockContract((await ethers.getSigners())[0], [ + beacon = await deployMockContract((await ethers.getSigners())[0], [ 'function getImplementation () external view returns (address)', ]); - await manager.mock.getImplementation.returns( + await beacon.mock.getImplementation.returns( await implementationInstance.getAddress(), ); @@ -33,13 +33,13 @@ describe('ManagedProxy', () => { 4, ); - instance = await new ManagedProxyMock__factory(deployer).deploy( - manager.address, + instance = await new BeaconProxyMock__factory(deployer).deploy( + beacon.address, selector, ); }); - describeBehaviorOfManagedProxy(async () => instance, { + describeBehaviorOfBeaconProxy(async () => instance, { implementationFunction: 'owner()', implementationFunctionArgs: [], }); @@ -52,21 +52,21 @@ describe('ManagedProxy', () => { }); describe('reverts if', () => { - it('manager is non-contract address', async () => { - await instance.setManager(ethers.ZeroAddress); + it('beacon is non-contract address', async () => { + await instance.setBeacon(ethers.ZeroAddress); await expect(instance.__getImplementation.staticCall()).to.be .reverted; }); - it('manager fails to return implementation', async () => { - await manager.mock.getImplementation.revertsWithReason('ERROR'); + it('beacon fails to return implementation', async () => { + await beacon.mock.getImplementation.revertsWithReason('ERROR'); await expect( instance.__getImplementation.staticCall(), ).to.be.revertedWithCustomError( instance, - 'ManagedProxy__FetchImplementationFailed', + 'BeaconProxy__FetchImplementationFailed', ); }); }); diff --git a/test/proxy/managed/ManagedProxyOwnable.ts b/test/proxy/beacon/BeaconProxyOwnable.ts similarity index 61% rename from test/proxy/managed/ManagedProxyOwnable.ts rename to test/proxy/beacon/BeaconProxyOwnable.ts index a51d8f6d..3700e732 100644 --- a/test/proxy/managed/ManagedProxyOwnable.ts +++ b/test/proxy/beacon/BeaconProxyOwnable.ts @@ -1,21 +1,21 @@ import { deployMockContract } from '@solidstate/library'; -import { describeBehaviorOfManagedProxyOwnable } from '@solidstate/spec'; +import { describeBehaviorOfBeaconProxyOwnable } from '@solidstate/spec'; import { - ManagedProxyOwnableMock, - ManagedProxyOwnableMock__factory, + BeaconProxyOwnableMock, + BeaconProxyOwnableMock__factory, OwnableMock__factory, } from '@solidstate/typechain-types'; import { expect } from 'chai'; import { ethers } from 'hardhat'; -describe('ManagedProxyOwnable', () => { - let manager: any; - let instance: ManagedProxyOwnableMock; +describe('BeaconProxyOwnable', () => { + let beacon: any; + let instance: BeaconProxyOwnableMock; beforeEach(async () => { const [deployer] = await ethers.getSigners(); - manager = await deployMockContract((await ethers.getSigners())[0], [ + beacon = await deployMockContract((await ethers.getSigners())[0], [ 'function getImplementation () external view returns (address)', ]); @@ -23,7 +23,7 @@ describe('ManagedProxyOwnable', () => { deployer, ).deploy(deployer.address); - await manager.mock.getImplementation.returns( + await beacon.mock.getImplementation.returns( await implementationInstance.getAddress(), ); @@ -33,13 +33,13 @@ describe('ManagedProxyOwnable', () => { 4, ); - instance = await new ManagedProxyOwnableMock__factory(deployer).deploy( - manager.address, + instance = await new BeaconProxyOwnableMock__factory(deployer).deploy( + beacon.address, selector, ); }); - describeBehaviorOfManagedProxyOwnable(async () => instance, { + describeBehaviorOfBeaconProxyOwnable(async () => instance, { implementationFunction: 'owner()', implementationFunctionArgs: [], }); @@ -49,29 +49,29 @@ describe('ManagedProxyOwnable', () => { it('returns implementation address'); describe('reverts if', () => { - it('manager is non-contract address', async () => { + it('beacon is non-contract address', async () => { await instance.setOwner(ethers.ZeroAddress); await expect(instance.__getImplementation.staticCall()).to.be .reverted; }); - it('manager fails to return implementation', async () => { - await manager.mock.getImplementation.revertsWithReason('ERROR'); + it('beacon fails to return implementation', async () => { + await beacon.mock.getImplementation.revertsWithReason('ERROR'); await expect( instance.__getImplementation.staticCall(), ).to.be.revertedWithCustomError( instance, - 'ManagedProxy__FetchImplementationFailed', + 'BeaconProxy__FetchImplementationFailed', ); }); }); }); - describe('#_getManager()', () => { + describe('#_getBeacon()', () => { it('returns address of ERC173 owner', async () => { - expect(await instance.__getManager.staticCall()).to.equal( + expect(await instance.__getBeacon.staticCall()).to.equal( await instance.getOwner.staticCall(), ); }); From c4d5750b94e6007b3a028cea34a698b06ed60e32 Mon Sep 17 00:00:00 2001 From: Nick Barry Date: Fri, 13 Oct 2023 20:39:26 -0400 Subject: [PATCH 02/10] add Beacon contract --- abi/Beacon.json | 83 +++++++++++++++++++ abi/BeaconInternal.json | 31 +++++++ abi/IBeacon.json | 83 +++++++++++++++++++ abi/IBeaconInternal.json | 31 +++++++ contracts/proxy/beacon/Beacon.sol | 27 ++++++ contracts/proxy/beacon/BeaconInternal.sol | 32 +++++++ contracts/proxy/beacon/BeaconProxy.sol | 22 ++--- contracts/proxy/beacon/BeaconProxyMock.sol | 5 +- .../proxy/beacon/BeaconProxyOwnableMock.sol | 5 +- contracts/proxy/beacon/BeaconStorage.sol | 19 +++++ contracts/proxy/beacon/IBeacon.sol | 20 +++++ contracts/proxy/beacon/IBeaconInternal.sol | 7 ++ 12 files changed, 343 insertions(+), 22 deletions(-) create mode 100644 abi/Beacon.json create mode 100644 abi/BeaconInternal.json create mode 100644 abi/IBeacon.json create mode 100644 abi/IBeaconInternal.json create mode 100644 contracts/proxy/beacon/Beacon.sol create mode 100644 contracts/proxy/beacon/BeaconInternal.sol create mode 100644 contracts/proxy/beacon/BeaconStorage.sol create mode 100644 contracts/proxy/beacon/IBeacon.sol create mode 100644 contracts/proxy/beacon/IBeaconInternal.sol diff --git a/abi/Beacon.json b/abi/Beacon.json new file mode 100644 index 00000000..135dd8d1 --- /dev/null +++ b/abi/Beacon.json @@ -0,0 +1,83 @@ +[ + { + "inputs": [], + "name": "Ownable__NotOwner", + "type": "error" + }, + { + "inputs": [], + "name": "Ownable__NotTransitiveOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abi/BeaconInternal.json b/abi/BeaconInternal.json new file mode 100644 index 00000000..7f336963 --- /dev/null +++ b/abi/BeaconInternal.json @@ -0,0 +1,31 @@ +[ + { + "inputs": [], + "name": "Ownable__NotOwner", + "type": "error" + }, + { + "inputs": [], + "name": "Ownable__NotTransitiveOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + } +] diff --git a/abi/IBeacon.json b/abi/IBeacon.json new file mode 100644 index 00000000..135dd8d1 --- /dev/null +++ b/abi/IBeacon.json @@ -0,0 +1,83 @@ +[ + { + "inputs": [], + "name": "Ownable__NotOwner", + "type": "error" + }, + { + "inputs": [], + "name": "Ownable__NotTransitiveOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abi/IBeaconInternal.json b/abi/IBeaconInternal.json new file mode 100644 index 00000000..7f336963 --- /dev/null +++ b/abi/IBeaconInternal.json @@ -0,0 +1,31 @@ +[ + { + "inputs": [], + "name": "Ownable__NotOwner", + "type": "error" + }, + { + "inputs": [], + "name": "Ownable__NotTransitiveOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + } +] diff --git a/contracts/proxy/beacon/Beacon.sol b/contracts/proxy/beacon/Beacon.sol new file mode 100644 index 00000000..79c1cbbd --- /dev/null +++ b/contracts/proxy/beacon/Beacon.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { Ownable } from '../../access/ownable/Ownable.sol'; +import { IBeacon } from './IBeacon.sol'; +import { BeaconInternal } from './BeaconInternal.sol'; + +contract Beacon is IBeacon, Ownable, BeaconInternal { + /** + * @inheritdoc IBeacon + */ + function getImplementation() + external + view + returns (address implementation) + { + implementation = _getImplementation(); + } + + /** + * @inheritdoc IBeacon + */ + function setImplementation(address implementation) external { + _setImplementation(implementation); + } +} diff --git a/contracts/proxy/beacon/BeaconInternal.sol b/contracts/proxy/beacon/BeaconInternal.sol new file mode 100644 index 00000000..c3f142f6 --- /dev/null +++ b/contracts/proxy/beacon/BeaconInternal.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { OwnableInternal } from '../../access/ownable/OwnableInternal.sol'; +import { IBeaconInternal } from './IBeaconInternal.sol'; +import { BeaconStorage } from './BeaconStorage.sol'; + +abstract contract BeaconInternal is IBeaconInternal, OwnableInternal { + /** + * @notice query the address of the implementation that should be used by BeaconProxy instancesf + * @return implementation address of the implementation contract + */ + function _getImplementation() + internal + view + virtual + returns (address implementation) + { + implementation = BeaconStorage.layout().implementation; + } + + /** + * @notice set the address of the implementation that should be used by BeaconProxy instancesf + * @param implementation address of the implementation contract + */ + function _setImplementation( + address implementation + ) internal virtual onlyOwner { + BeaconStorage.layout().implementation = implementation; + } +} diff --git a/contracts/proxy/beacon/BeaconProxy.sol b/contracts/proxy/beacon/BeaconProxy.sol index 995f7885..49ceedaa 100644 --- a/contracts/proxy/beacon/BeaconProxy.sol +++ b/contracts/proxy/beacon/BeaconProxy.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.8; import { Proxy } from '../Proxy.sol'; +import { IBeacon } from './IBeacon.sol'; import { IBeaconProxy } from './IBeaconProxy.sol'; /** @@ -10,24 +11,17 @@ import { IBeaconProxy } from './IBeaconProxy.sol'; * @dev implementation fetched using immutable function selector */ abstract contract BeaconProxy is IBeaconProxy, Proxy { - bytes4 internal immutable FETCH_IMPLEMENTATION_SELECTOR; - - /** - * @param fetchImplementationSelector function selector used to fetch implementation from beacon - */ - constructor(bytes4 fetchImplementationSelector) { - FETCH_IMPLEMENTATION_SELECTOR = fetchImplementationSelector; - } - /** * @inheritdoc Proxy */ function _getImplementation() internal view override returns (address) { - (bool success, bytes memory data) = _getBeacon().staticcall( - abi.encodePacked(FETCH_IMPLEMENTATION_SELECTOR) - ); - if (!success) revert BeaconProxy__FetchImplementationFailed(); - return abi.decode(data, (address)); + try IBeacon(_getBeacon()).getImplementation() returns ( + address implementation + ) { + return implementation; + } catch { + revert BeaconProxy__FetchImplementationFailed(); + } } /** diff --git a/contracts/proxy/beacon/BeaconProxyMock.sol b/contracts/proxy/beacon/BeaconProxyMock.sol index da063433..f83ccf67 100644 --- a/contracts/proxy/beacon/BeaconProxyMock.sol +++ b/contracts/proxy/beacon/BeaconProxyMock.sol @@ -7,10 +7,7 @@ import { BeaconProxy } from './BeaconProxy.sol'; contract BeaconProxyMock is BeaconProxy { address private _beacon; - constructor( - address beacon, - bytes4 fetchImplementationSelector - ) BeaconProxy(fetchImplementationSelector) { + constructor(address beacon, bytes4 fetchImplementationSelector) { setBeacon(beacon); } diff --git a/contracts/proxy/beacon/BeaconProxyOwnableMock.sol b/contracts/proxy/beacon/BeaconProxyOwnableMock.sol index 10dca021..52d670c6 100644 --- a/contracts/proxy/beacon/BeaconProxyOwnableMock.sol +++ b/contracts/proxy/beacon/BeaconProxyOwnableMock.sol @@ -5,10 +5,7 @@ pragma solidity ^0.8.8; import { BeaconProxy, BeaconProxyOwnable } from './BeaconProxyOwnable.sol'; contract BeaconProxyOwnableMock is BeaconProxyOwnable { - constructor( - address beacon, - bytes4 fetchImplementationSelector - ) BeaconProxy(fetchImplementationSelector) { + constructor(address beacon, bytes4 fetchImplementationSelector) { setOwner(beacon); } diff --git a/contracts/proxy/beacon/BeaconStorage.sol b/contracts/proxy/beacon/BeaconStorage.sol new file mode 100644 index 00000000..168da8d4 --- /dev/null +++ b/contracts/proxy/beacon/BeaconStorage.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.8; + +library BeaconStorage { + struct Layout { + address implementation; + } + + bytes32 internal constant STORAGE_SLOT = + keccak256('solidstate.contracts.storage.Beacon'); + + function layout() internal pure returns (Layout storage l) { + bytes32 slot = STORAGE_SLOT; + assembly { + l.slot := slot + } + } +} diff --git a/contracts/proxy/beacon/IBeacon.sol b/contracts/proxy/beacon/IBeacon.sol new file mode 100644 index 00000000..3163588d --- /dev/null +++ b/contracts/proxy/beacon/IBeacon.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { IOwnable } from '../../access/ownable/IOwnable.sol'; +import { BeaconStorage } from './BeaconStorage.sol'; + +interface IBeacon is IOwnable { + /** + * @notice query the address of the implementation that should be used by BeaconProxy instancesf + * @return implementation address of the implementation contract + */ + function getImplementation() external view returns (address implementation); + + /** + * @notice set the address of the implementation that should be used by BeaconProxy instancesf + * @param implementation address of the implementation contract + */ + function setImplementation(address implementation) external; +} diff --git a/contracts/proxy/beacon/IBeaconInternal.sol b/contracts/proxy/beacon/IBeaconInternal.sol new file mode 100644 index 00000000..9495d215 --- /dev/null +++ b/contracts/proxy/beacon/IBeaconInternal.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { IOwnableInternal } from '../../access/ownable/IOwnableInternal.sol'; + +interface IBeaconInternal is IOwnableInternal {} From 683cac47a58a695dce71e3e2fe016ee1e8dc0cb2 Mon Sep 17 00:00:00 2001 From: Nick Barry Date: Fri, 13 Oct 2023 20:46:34 -0400 Subject: [PATCH 03/10] remove BeaconProxyOwnable --- abi/BeaconProxyOwnable.json | 45 ----------- abi/IBeaconProxyOwnable.json | 16 ---- contracts/proxy/beacon/BeaconProxyOwnable.sol | 23 ------ .../proxy/beacon/BeaconProxyOwnableMock.sol | 32 -------- .../proxy/beacon/IBeaconProxyOwnable.sol | 7 -- .../beacon/BeaconProxyOwnable.behavior.ts | 31 ------- spec/proxy/beacon/index.ts | 1 - test/proxy/beacon/BeaconProxyOwnable.ts | 80 ------------------- 8 files changed, 235 deletions(-) delete mode 100644 abi/BeaconProxyOwnable.json delete mode 100644 abi/IBeaconProxyOwnable.json delete mode 100644 contracts/proxy/beacon/BeaconProxyOwnable.sol delete mode 100644 contracts/proxy/beacon/BeaconProxyOwnableMock.sol delete mode 100644 contracts/proxy/beacon/IBeaconProxyOwnable.sol delete mode 100644 spec/proxy/beacon/BeaconProxyOwnable.behavior.ts delete mode 100644 test/proxy/beacon/BeaconProxyOwnable.ts diff --git a/abi/BeaconProxyOwnable.json b/abi/BeaconProxyOwnable.json deleted file mode 100644 index 4398641d..00000000 --- a/abi/BeaconProxyOwnable.json +++ /dev/null @@ -1,45 +0,0 @@ -[ - { - "inputs": [], - "name": "BeaconProxy__FetchImplementationFailed", - "type": "error" - }, - { - "inputs": [], - "name": "Ownable__NotOwner", - "type": "error" - }, - { - "inputs": [], - "name": "Ownable__NotTransitiveOwner", - "type": "error" - }, - { - "inputs": [], - "name": "Proxy__ImplementationIsNotContract", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "stateMutability": "payable", - "type": "fallback" - } -] diff --git a/abi/IBeaconProxyOwnable.json b/abi/IBeaconProxyOwnable.json deleted file mode 100644 index cc399d94..00000000 --- a/abi/IBeaconProxyOwnable.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "inputs": [], - "name": "BeaconProxy__FetchImplementationFailed", - "type": "error" - }, - { - "inputs": [], - "name": "Proxy__ImplementationIsNotContract", - "type": "error" - }, - { - "stateMutability": "payable", - "type": "fallback" - } -] diff --git a/contracts/proxy/beacon/BeaconProxyOwnable.sol b/contracts/proxy/beacon/BeaconProxyOwnable.sol deleted file mode 100644 index 5a8a4754..00000000 --- a/contracts/proxy/beacon/BeaconProxyOwnable.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.8; - -import { OwnableInternal } from '../../access/ownable/OwnableInternal.sol'; -import { IBeaconProxyOwnable } from './IBeaconProxyOwnable.sol'; -import { BeaconProxy } from './BeaconProxy.sol'; - -/** - * @title Proxy with implementation controlled by ERC171 owner - */ -abstract contract BeaconProxyOwnable is - IBeaconProxyOwnable, - BeaconProxy, - OwnableInternal -{ - /** - * @inheritdoc BeaconProxy - */ - function _getBeacon() internal view override returns (address) { - return _owner(); - } -} diff --git a/contracts/proxy/beacon/BeaconProxyOwnableMock.sol b/contracts/proxy/beacon/BeaconProxyOwnableMock.sol deleted file mode 100644 index 52d670c6..00000000 --- a/contracts/proxy/beacon/BeaconProxyOwnableMock.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.8; - -import { BeaconProxy, BeaconProxyOwnable } from './BeaconProxyOwnable.sol'; - -contract BeaconProxyOwnableMock is BeaconProxyOwnable { - constructor(address beacon, bytes4 fetchImplementationSelector) { - setOwner(beacon); - } - - function __getImplementation() external view returns (address) { - return _getImplementation(); - } - - function __getBeacon() external view returns (address) { - return _getBeacon(); - } - - function getOwner() external view returns (address) { - return _owner(); - } - - function setOwner(address owner) public { - _setOwner(owner); - } - - /** - * @dev suppress compiler warning - */ - receive() external payable {} -} diff --git a/contracts/proxy/beacon/IBeaconProxyOwnable.sol b/contracts/proxy/beacon/IBeaconProxyOwnable.sol deleted file mode 100644 index 989bdd4f..00000000 --- a/contracts/proxy/beacon/IBeaconProxyOwnable.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.8; - -import { IBeaconProxy } from './IBeaconProxy.sol'; - -interface IBeaconProxyOwnable is IBeaconProxy {} diff --git a/spec/proxy/beacon/BeaconProxyOwnable.behavior.ts b/spec/proxy/beacon/BeaconProxyOwnable.behavior.ts deleted file mode 100644 index 40943e81..00000000 --- a/spec/proxy/beacon/BeaconProxyOwnable.behavior.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - describeBehaviorOfBeaconProxy, - BeaconProxyBehaviorArgs, -} from './BeaconProxy.behavior'; -import { describeFilter } from '@solidstate/library'; -import { IBeaconProxyOwnable } from '@solidstate/typechain-types'; - -export interface BeaconProxyOwnableBehaviorArgs - extends BeaconProxyBehaviorArgs {} - -export function describeBehaviorOfBeaconProxyOwnable( - deploy: () => Promise, - { - implementationFunction, - implementationFunctionArgs, - }: BeaconProxyOwnableBehaviorArgs, - skips?: string[], -) { - const describe = describeFilter(skips); - - describe('::BeaconProxyOwnable', () => { - describeBehaviorOfBeaconProxy( - deploy, - { - implementationFunction, - implementationFunctionArgs, - }, - [], - ); - }); -} diff --git a/spec/proxy/beacon/index.ts b/spec/proxy/beacon/index.ts index 7aa3942c..89e19604 100644 --- a/spec/proxy/beacon/index.ts +++ b/spec/proxy/beacon/index.ts @@ -1,2 +1 @@ export * from './BeaconProxy.behavior'; -export * from './BeaconProxyOwnable.behavior'; diff --git a/test/proxy/beacon/BeaconProxyOwnable.ts b/test/proxy/beacon/BeaconProxyOwnable.ts deleted file mode 100644 index 3700e732..00000000 --- a/test/proxy/beacon/BeaconProxyOwnable.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { deployMockContract } from '@solidstate/library'; -import { describeBehaviorOfBeaconProxyOwnable } from '@solidstate/spec'; -import { - BeaconProxyOwnableMock, - BeaconProxyOwnableMock__factory, - OwnableMock__factory, -} from '@solidstate/typechain-types'; -import { expect } from 'chai'; -import { ethers } from 'hardhat'; - -describe('BeaconProxyOwnable', () => { - let beacon: any; - let instance: BeaconProxyOwnableMock; - - beforeEach(async () => { - const [deployer] = await ethers.getSigners(); - - beacon = await deployMockContract((await ethers.getSigners())[0], [ - 'function getImplementation () external view returns (address)', - ]); - - const implementationInstance = await new OwnableMock__factory( - deployer, - ).deploy(deployer.address); - - await beacon.mock.getImplementation.returns( - await implementationInstance.getAddress(), - ); - - const selector = ethers.dataSlice( - ethers.solidityPackedKeccak256(['string'], ['getImplementation()']), - 0, - 4, - ); - - instance = await new BeaconProxyOwnableMock__factory(deployer).deploy( - beacon.address, - selector, - ); - }); - - describeBehaviorOfBeaconProxyOwnable(async () => instance, { - implementationFunction: 'owner()', - implementationFunctionArgs: [], - }); - - describe('__internal', () => { - describe('#_getImplementation()', () => { - it('returns implementation address'); - - describe('reverts if', () => { - it('beacon is non-contract address', async () => { - await instance.setOwner(ethers.ZeroAddress); - - await expect(instance.__getImplementation.staticCall()).to.be - .reverted; - }); - - it('beacon fails to return implementation', async () => { - await beacon.mock.getImplementation.revertsWithReason('ERROR'); - - await expect( - instance.__getImplementation.staticCall(), - ).to.be.revertedWithCustomError( - instance, - 'BeaconProxy__FetchImplementationFailed', - ); - }); - }); - }); - - describe('#_getBeacon()', () => { - it('returns address of ERC173 owner', async () => { - expect(await instance.__getBeacon.staticCall()).to.equal( - await instance.getOwner.staticCall(), - ); - }); - }); - }); -}); From e577f8f73f9b4e341b531ed32980c07ca7f855f9 Mon Sep 17 00:00:00 2001 From: Nick Barry Date: Fri, 13 Oct 2023 21:02:28 -0400 Subject: [PATCH 04/10] remove selector argument from BeaconProxy mock and tests --- contracts/proxy/beacon/BeaconProxyMock.sol | 2 +- test/proxy/beacon/BeaconProxy.ts | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/contracts/proxy/beacon/BeaconProxyMock.sol b/contracts/proxy/beacon/BeaconProxyMock.sol index f83ccf67..7413fb61 100644 --- a/contracts/proxy/beacon/BeaconProxyMock.sol +++ b/contracts/proxy/beacon/BeaconProxyMock.sol @@ -7,7 +7,7 @@ import { BeaconProxy } from './BeaconProxy.sol'; contract BeaconProxyMock is BeaconProxy { address private _beacon; - constructor(address beacon, bytes4 fetchImplementationSelector) { + constructor(address beacon) { setBeacon(beacon); } diff --git a/test/proxy/beacon/BeaconProxy.ts b/test/proxy/beacon/BeaconProxy.ts index 7543c9b1..2d12436c 100644 --- a/test/proxy/beacon/BeaconProxy.ts +++ b/test/proxy/beacon/BeaconProxy.ts @@ -27,15 +27,8 @@ describe('BeaconProxy', () => { await implementationInstance.getAddress(), ); - const selector = ethers.dataSlice( - ethers.solidityPackedKeccak256(['string'], ['getImplementation()']), - 0, - 4, - ); - instance = await new BeaconProxyMock__factory(deployer).deploy( beacon.address, - selector, ); }); From fa4b7617f5aad0bb209651037db882a901cdf9be Mon Sep 17 00:00:00 2001 From: Nick Barry Date: Fri, 13 Oct 2023 21:08:57 -0400 Subject: [PATCH 05/10] remove BeaconProxy__FetchImplementationFailed error --- abi/BeaconProxy.json | 5 ----- abi/IBeaconProxy.json | 5 ----- contracts/proxy/beacon/BeaconProxy.sol | 8 +------- contracts/proxy/beacon/IBeaconProxy.sol | 4 +--- test/proxy/beacon/BeaconProxy.ts | 11 ----------- 5 files changed, 2 insertions(+), 31 deletions(-) diff --git a/abi/BeaconProxy.json b/abi/BeaconProxy.json index cc399d94..7661f993 100644 --- a/abi/BeaconProxy.json +++ b/abi/BeaconProxy.json @@ -1,9 +1,4 @@ [ - { - "inputs": [], - "name": "BeaconProxy__FetchImplementationFailed", - "type": "error" - }, { "inputs": [], "name": "Proxy__ImplementationIsNotContract", diff --git a/abi/IBeaconProxy.json b/abi/IBeaconProxy.json index cc399d94..7661f993 100644 --- a/abi/IBeaconProxy.json +++ b/abi/IBeaconProxy.json @@ -1,9 +1,4 @@ [ - { - "inputs": [], - "name": "BeaconProxy__FetchImplementationFailed", - "type": "error" - }, { "inputs": [], "name": "Proxy__ImplementationIsNotContract", diff --git a/contracts/proxy/beacon/BeaconProxy.sol b/contracts/proxy/beacon/BeaconProxy.sol index 49ceedaa..81e09464 100644 --- a/contracts/proxy/beacon/BeaconProxy.sol +++ b/contracts/proxy/beacon/BeaconProxy.sol @@ -15,13 +15,7 @@ abstract contract BeaconProxy is IBeaconProxy, Proxy { * @inheritdoc Proxy */ function _getImplementation() internal view override returns (address) { - try IBeacon(_getBeacon()).getImplementation() returns ( - address implementation - ) { - return implementation; - } catch { - revert BeaconProxy__FetchImplementationFailed(); - } + return IBeacon(_getBeacon()).getImplementation(); } /** diff --git a/contracts/proxy/beacon/IBeaconProxy.sol b/contracts/proxy/beacon/IBeaconProxy.sol index 702cc8ed..c6e59e17 100644 --- a/contracts/proxy/beacon/IBeaconProxy.sol +++ b/contracts/proxy/beacon/IBeaconProxy.sol @@ -4,6 +4,4 @@ pragma solidity ^0.8.8; import { IProxy } from '../IProxy.sol'; -interface IBeaconProxy is IProxy { - error BeaconProxy__FetchImplementationFailed(); -} +interface IBeaconProxy is IProxy {} diff --git a/test/proxy/beacon/BeaconProxy.ts b/test/proxy/beacon/BeaconProxy.ts index 2d12436c..ab1df9cc 100644 --- a/test/proxy/beacon/BeaconProxy.ts +++ b/test/proxy/beacon/BeaconProxy.ts @@ -51,17 +51,6 @@ describe('BeaconProxy', () => { await expect(instance.__getImplementation.staticCall()).to.be .reverted; }); - - it('beacon fails to return implementation', async () => { - await beacon.mock.getImplementation.revertsWithReason('ERROR'); - - await expect( - instance.__getImplementation.staticCall(), - ).to.be.revertedWithCustomError( - instance, - 'BeaconProxy__FetchImplementationFailed', - ); - }); }); }); }); From d99017448f87d36e37e6e00bccc52ba378e9df81 Mon Sep 17 00:00:00 2001 From: Nick Barry Date: Fri, 1 Dec 2023 18:14:51 -0500 Subject: [PATCH 06/10] add DiamondBeacon contracts --- abi/DiamondBeacon.json | 255 ++++++++++++++++++ abi/DiamondBeaconInternal.json | 31 +++ abi/DiamondBeaconProxy.json | 11 + abi/IDiamondBeacon.json | 255 ++++++++++++++++++ abi/IDiamondBeaconInternal.json | 31 +++ contracts/proxy/beacon/BeaconProxy.sol | 8 +- contracts/proxy/beacon/DiamondBeacon.sol | 24 ++ .../proxy/beacon/DiamondBeaconInternal.sol | 7 + contracts/proxy/beacon/DiamondBeaconProxy.sol | 12 + contracts/proxy/beacon/IDiamondBeacon.sol | 15 ++ .../proxy/beacon/IDiamondBeaconInternal.sol | 7 + 11 files changed, 655 insertions(+), 1 deletion(-) create mode 100644 abi/DiamondBeacon.json create mode 100644 abi/DiamondBeaconInternal.json create mode 100644 abi/DiamondBeaconProxy.json create mode 100644 abi/IDiamondBeacon.json create mode 100644 abi/IDiamondBeaconInternal.json create mode 100644 contracts/proxy/beacon/DiamondBeacon.sol create mode 100644 contracts/proxy/beacon/DiamondBeaconInternal.sol create mode 100644 contracts/proxy/beacon/DiamondBeaconProxy.sol create mode 100644 contracts/proxy/beacon/IDiamondBeacon.sol create mode 100644 contracts/proxy/beacon/IDiamondBeaconInternal.sol diff --git a/abi/DiamondBeacon.json b/abi/DiamondBeacon.json new file mode 100644 index 00000000..aa5b112e --- /dev/null +++ b/abi/DiamondBeacon.json @@ -0,0 +1,255 @@ +[ + { + "inputs": [], + "name": "DiamondWritable__InvalidInitializationParameters", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__RemoveTargetNotZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__ReplaceTargetIsIdentical", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__SelectorAlreadyAdded", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__SelectorIsImmutable", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__SelectorNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__SelectorNotSpecified", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__TargetHasNoCode", + "type": "error" + }, + { + "inputs": [], + "name": "Ownable__NotOwner", + "type": "error" + }, + { + "inputs": [], + "name": "Ownable__NotTransitiveOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "enum IDiamondWritableInternal.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamondWritableInternal.FacetCut[]", + "name": "facetCuts", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "enum IDiamondWritableInternal.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondWritableInternal.FacetCut[]", + "name": "facetCuts", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "addresses", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondReadable.Facet[]", + "name": "diamondFacets", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abi/DiamondBeaconInternal.json b/abi/DiamondBeaconInternal.json new file mode 100644 index 00000000..7f336963 --- /dev/null +++ b/abi/DiamondBeaconInternal.json @@ -0,0 +1,31 @@ +[ + { + "inputs": [], + "name": "Ownable__NotOwner", + "type": "error" + }, + { + "inputs": [], + "name": "Ownable__NotTransitiveOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + } +] diff --git a/abi/DiamondBeaconProxy.json b/abi/DiamondBeaconProxy.json new file mode 100644 index 00000000..7661f993 --- /dev/null +++ b/abi/DiamondBeaconProxy.json @@ -0,0 +1,11 @@ +[ + { + "inputs": [], + "name": "Proxy__ImplementationIsNotContract", + "type": "error" + }, + { + "stateMutability": "payable", + "type": "fallback" + } +] diff --git a/abi/IDiamondBeacon.json b/abi/IDiamondBeacon.json new file mode 100644 index 00000000..aa5b112e --- /dev/null +++ b/abi/IDiamondBeacon.json @@ -0,0 +1,255 @@ +[ + { + "inputs": [], + "name": "DiamondWritable__InvalidInitializationParameters", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__RemoveTargetNotZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__ReplaceTargetIsIdentical", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__SelectorAlreadyAdded", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__SelectorIsImmutable", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__SelectorNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__SelectorNotSpecified", + "type": "error" + }, + { + "inputs": [], + "name": "DiamondWritable__TargetHasNoCode", + "type": "error" + }, + { + "inputs": [], + "name": "Ownable__NotOwner", + "type": "error" + }, + { + "inputs": [], + "name": "Ownable__NotTransitiveOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "enum IDiamondWritableInternal.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamondWritableInternal.FacetCut[]", + "name": "facetCuts", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "enum IDiamondWritableInternal.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondWritableInternal.FacetCut[]", + "name": "facetCuts", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "addresses", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondReadable.Facet[]", + "name": "diamondFacets", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abi/IDiamondBeaconInternal.json b/abi/IDiamondBeaconInternal.json new file mode 100644 index 00000000..7f336963 --- /dev/null +++ b/abi/IDiamondBeaconInternal.json @@ -0,0 +1,31 @@ +[ + { + "inputs": [], + "name": "Ownable__NotOwner", + "type": "error" + }, + { + "inputs": [], + "name": "Ownable__NotTransitiveOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + } +] diff --git a/contracts/proxy/beacon/BeaconProxy.sol b/contracts/proxy/beacon/BeaconProxy.sol index 81e09464..60d26e1a 100644 --- a/contracts/proxy/beacon/BeaconProxy.sol +++ b/contracts/proxy/beacon/BeaconProxy.sol @@ -14,7 +14,13 @@ abstract contract BeaconProxy is IBeaconProxy, Proxy { /** * @inheritdoc Proxy */ - function _getImplementation() internal view override returns (address) { + function _getImplementation() + internal + view + virtual + override + returns (address) + { return IBeacon(_getBeacon()).getImplementation(); } diff --git a/contracts/proxy/beacon/DiamondBeacon.sol b/contracts/proxy/beacon/DiamondBeacon.sol new file mode 100644 index 00000000..9125b210 --- /dev/null +++ b/contracts/proxy/beacon/DiamondBeacon.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { OwnableInternal } from '../../access/ownable/Ownable.sol'; +import { Ownable } from '../../access/ownable/Ownable.sol'; +import { DiamondReadable } from '../diamond/readable/DiamondReadable.sol'; +import { DiamondWritable } from '../diamond/writable/DiamondWritable.sol'; +import { IDiamondBeacon } from './IDiamondBeacon.sol'; +import { DiamondBeaconInternal } from './DiamondBeaconInternal.sol'; + +/** + * @title Beacon contract which imitates the upgrade mechanism of an EIP-2535 diamond proxy. + * @dev Configure this beacon using diamondCut as if it were a diamond proxy. Proxies can fetch their implementations by calling facetAddress. + */ +contract DiamondBeacon is + IDiamondBeacon, + DiamondBeaconInternal, + DiamondReadable, + DiamondWritable, + Ownable +{ + +} diff --git a/contracts/proxy/beacon/DiamondBeaconInternal.sol b/contracts/proxy/beacon/DiamondBeaconInternal.sol new file mode 100644 index 00000000..83443d98 --- /dev/null +++ b/contracts/proxy/beacon/DiamondBeaconInternal.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { IDiamondBeaconInternal } from './IDiamondBeaconInternal.sol'; + +abstract contract DiamondBeaconInternal is IDiamondBeaconInternal {} diff --git a/contracts/proxy/beacon/DiamondBeaconProxy.sol b/contracts/proxy/beacon/DiamondBeaconProxy.sol new file mode 100644 index 00000000..fd689cdc --- /dev/null +++ b/contracts/proxy/beacon/DiamondBeaconProxy.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { BeaconProxy } from './BeaconProxy.sol'; +import { IDiamondBeacon } from './IDiamondBeacon.sol'; + +abstract contract DiamondBeaconProxy is BeaconProxy { + function _getImplementation() internal view override returns (address) { + return IDiamondBeacon(_getBeacon()).facetAddress(msg.sig); + } +} diff --git a/contracts/proxy/beacon/IDiamondBeacon.sol b/contracts/proxy/beacon/IDiamondBeacon.sol new file mode 100644 index 00000000..99b6a69e --- /dev/null +++ b/contracts/proxy/beacon/IDiamondBeacon.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { IOwnable } from '../../access/ownable/IOwnable.sol'; +import { IDiamondReadable } from '../diamond/readable/IDiamondReadable.sol'; +import { IDiamondWritable } from '../diamond/writable/IDiamondWritable.sol'; +import { IDiamondBeaconInternal } from './IDiamondBeaconInternal.sol'; + +interface IDiamondBeacon is + IDiamondReadable, + IDiamondWritable, + IOwnable, + IDiamondBeaconInternal +{} diff --git a/contracts/proxy/beacon/IDiamondBeaconInternal.sol b/contracts/proxy/beacon/IDiamondBeaconInternal.sol new file mode 100644 index 00000000..a15fe03c --- /dev/null +++ b/contracts/proxy/beacon/IDiamondBeaconInternal.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { IBeaconInternal } from './IBeaconInternal.sol'; + +interface IDiamondBeaconInternal is IBeaconInternal {} From fa193f10c57d65bf294afc3f2e29917733a41faf Mon Sep 17 00:00:00 2001 From: Nick Barry Date: Sun, 10 Dec 2023 20:35:22 -0500 Subject: [PATCH 07/10] update version pragmas --- contracts/proxy/beacon/Beacon.sol | 2 +- contracts/proxy/beacon/BeaconInternal.sol | 2 +- contracts/proxy/beacon/BeaconProxy.sol | 2 +- contracts/proxy/beacon/BeaconProxyMock.sol | 2 +- contracts/proxy/beacon/BeaconStorage.sol | 2 +- contracts/proxy/beacon/DiamondBeacon.sol | 2 +- contracts/proxy/beacon/DiamondBeaconInternal.sol | 2 +- contracts/proxy/beacon/DiamondBeaconProxy.sol | 2 +- contracts/proxy/beacon/IBeacon.sol | 2 +- contracts/proxy/beacon/IBeaconInternal.sol | 2 +- contracts/proxy/beacon/IDiamondBeacon.sol | 2 +- contracts/proxy/beacon/IDiamondBeaconInternal.sol | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/contracts/proxy/beacon/Beacon.sol b/contracts/proxy/beacon/Beacon.sol index 79c1cbbd..22439d8a 100644 --- a/contracts/proxy/beacon/Beacon.sol +++ b/contracts/proxy/beacon/Beacon.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.18; import { Ownable } from '../../access/ownable/Ownable.sol'; import { IBeacon } from './IBeacon.sol'; diff --git a/contracts/proxy/beacon/BeaconInternal.sol b/contracts/proxy/beacon/BeaconInternal.sol index c3f142f6..89e25d30 100644 --- a/contracts/proxy/beacon/BeaconInternal.sol +++ b/contracts/proxy/beacon/BeaconInternal.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.18; import { OwnableInternal } from '../../access/ownable/OwnableInternal.sol'; import { IBeaconInternal } from './IBeaconInternal.sol'; diff --git a/contracts/proxy/beacon/BeaconProxy.sol b/contracts/proxy/beacon/BeaconProxy.sol index 60d26e1a..f037f11c 100644 --- a/contracts/proxy/beacon/BeaconProxy.sol +++ b/contracts/proxy/beacon/BeaconProxy.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.8; +pragma solidity ^0.8.18; import { Proxy } from '../Proxy.sol'; import { IBeacon } from './IBeacon.sol'; diff --git a/contracts/proxy/beacon/BeaconProxyMock.sol b/contracts/proxy/beacon/BeaconProxyMock.sol index 7413fb61..b18d6c81 100644 --- a/contracts/proxy/beacon/BeaconProxyMock.sol +++ b/contracts/proxy/beacon/BeaconProxyMock.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.8; +pragma solidity ^0.8.18; import { BeaconProxy } from './BeaconProxy.sol'; diff --git a/contracts/proxy/beacon/BeaconStorage.sol b/contracts/proxy/beacon/BeaconStorage.sol index 168da8d4..3889d401 100644 --- a/contracts/proxy/beacon/BeaconStorage.sol +++ b/contracts/proxy/beacon/BeaconStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.8; +pragma solidity ^0.8.18; library BeaconStorage { struct Layout { diff --git a/contracts/proxy/beacon/DiamondBeacon.sol b/contracts/proxy/beacon/DiamondBeacon.sol index 9125b210..abc1f4ee 100644 --- a/contracts/proxy/beacon/DiamondBeacon.sol +++ b/contracts/proxy/beacon/DiamondBeacon.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.18; import { OwnableInternal } from '../../access/ownable/Ownable.sol'; import { Ownable } from '../../access/ownable/Ownable.sol'; diff --git a/contracts/proxy/beacon/DiamondBeaconInternal.sol b/contracts/proxy/beacon/DiamondBeaconInternal.sol index 83443d98..864c0c3d 100644 --- a/contracts/proxy/beacon/DiamondBeaconInternal.sol +++ b/contracts/proxy/beacon/DiamondBeaconInternal.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.18; import { IDiamondBeaconInternal } from './IDiamondBeaconInternal.sol'; diff --git a/contracts/proxy/beacon/DiamondBeaconProxy.sol b/contracts/proxy/beacon/DiamondBeaconProxy.sol index fd689cdc..f2b95131 100644 --- a/contracts/proxy/beacon/DiamondBeaconProxy.sol +++ b/contracts/proxy/beacon/DiamondBeaconProxy.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.18; import { BeaconProxy } from './BeaconProxy.sol'; import { IDiamondBeacon } from './IDiamondBeacon.sol'; diff --git a/contracts/proxy/beacon/IBeacon.sol b/contracts/proxy/beacon/IBeacon.sol index 3163588d..2f7cfe13 100644 --- a/contracts/proxy/beacon/IBeacon.sol +++ b/contracts/proxy/beacon/IBeacon.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.18; import { IOwnable } from '../../access/ownable/IOwnable.sol'; import { BeaconStorage } from './BeaconStorage.sol'; diff --git a/contracts/proxy/beacon/IBeaconInternal.sol b/contracts/proxy/beacon/IBeaconInternal.sol index 9495d215..31ed4b0b 100644 --- a/contracts/proxy/beacon/IBeaconInternal.sol +++ b/contracts/proxy/beacon/IBeaconInternal.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.18; import { IOwnableInternal } from '../../access/ownable/IOwnableInternal.sol'; diff --git a/contracts/proxy/beacon/IDiamondBeacon.sol b/contracts/proxy/beacon/IDiamondBeacon.sol index 99b6a69e..355a4d37 100644 --- a/contracts/proxy/beacon/IDiamondBeacon.sol +++ b/contracts/proxy/beacon/IDiamondBeacon.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.18; import { IOwnable } from '../../access/ownable/IOwnable.sol'; import { IDiamondReadable } from '../diamond/readable/IDiamondReadable.sol'; diff --git a/contracts/proxy/beacon/IDiamondBeaconInternal.sol b/contracts/proxy/beacon/IDiamondBeaconInternal.sol index a15fe03c..0d1825dc 100644 --- a/contracts/proxy/beacon/IDiamondBeaconInternal.sol +++ b/contracts/proxy/beacon/IDiamondBeaconInternal.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.18; import { IBeaconInternal } from './IBeaconInternal.sol'; From 0e2b0d4481ac07cb19e5636d26ac9ea1efa730ae Mon Sep 17 00:00:00 2001 From: Nick Barry Date: Tue, 30 Jan 2024 03:37:09 +0200 Subject: [PATCH 08/10] update ABIs --- abi/DiamondBeacon.json | 10 +++++----- abi/IDiamondBeacon.json | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/abi/DiamondBeacon.json b/abi/DiamondBeacon.json index aa5b112e..1a717b98 100644 --- a/abi/DiamondBeacon.json +++ b/abi/DiamondBeacon.json @@ -60,7 +60,7 @@ "type": "address" }, { - "internalType": "enum IDiamondWritableInternal.FacetCutAction", + "internalType": "enum IERC2535DiamondCutInternal.FacetCutAction", "name": "action", "type": "uint8" }, @@ -71,7 +71,7 @@ } ], "indexed": false, - "internalType": "struct IDiamondWritableInternal.FacetCut[]", + "internalType": "struct IERC2535DiamondCutInternal.FacetCut[]", "name": "facetCuts", "type": "tuple[]" }, @@ -120,7 +120,7 @@ "type": "address" }, { - "internalType": "enum IDiamondWritableInternal.FacetCutAction", + "internalType": "enum IERC2535DiamondCutInternal.FacetCutAction", "name": "action", "type": "uint8" }, @@ -130,7 +130,7 @@ "type": "bytes4[]" } ], - "internalType": "struct IDiamondWritableInternal.FacetCut[]", + "internalType": "struct IERC2535DiamondCutInternal.FacetCut[]", "name": "facetCuts", "type": "tuple[]" }, @@ -218,7 +218,7 @@ "type": "bytes4[]" } ], - "internalType": "struct IDiamondReadable.Facet[]", + "internalType": "struct IERC2535DiamondLoupeInternal.Facet[]", "name": "diamondFacets", "type": "tuple[]" } diff --git a/abi/IDiamondBeacon.json b/abi/IDiamondBeacon.json index aa5b112e..1a717b98 100644 --- a/abi/IDiamondBeacon.json +++ b/abi/IDiamondBeacon.json @@ -60,7 +60,7 @@ "type": "address" }, { - "internalType": "enum IDiamondWritableInternal.FacetCutAction", + "internalType": "enum IERC2535DiamondCutInternal.FacetCutAction", "name": "action", "type": "uint8" }, @@ -71,7 +71,7 @@ } ], "indexed": false, - "internalType": "struct IDiamondWritableInternal.FacetCut[]", + "internalType": "struct IERC2535DiamondCutInternal.FacetCut[]", "name": "facetCuts", "type": "tuple[]" }, @@ -120,7 +120,7 @@ "type": "address" }, { - "internalType": "enum IDiamondWritableInternal.FacetCutAction", + "internalType": "enum IERC2535DiamondCutInternal.FacetCutAction", "name": "action", "type": "uint8" }, @@ -130,7 +130,7 @@ "type": "bytes4[]" } ], - "internalType": "struct IDiamondWritableInternal.FacetCut[]", + "internalType": "struct IERC2535DiamondCutInternal.FacetCut[]", "name": "facetCuts", "type": "tuple[]" }, @@ -218,7 +218,7 @@ "type": "bytes4[]" } ], - "internalType": "struct IDiamondReadable.Facet[]", + "internalType": "struct IERC2535DiamondLoupeInternal.Facet[]", "name": "diamondFacets", "type": "tuple[]" } From af757ee67214d7580686b3e55ae7cebc8846ef90 Mon Sep 17 00:00:00 2001 From: Nick Barry Date: Mon, 5 Feb 2024 22:46:54 +0200 Subject: [PATCH 09/10] addIDiamondBeaconProxy --- abi/IDiamondBeaconProxy.json | 11 +++++++++++ contracts/proxy/beacon/DiamondBeaconProxy.sol | 3 ++- contracts/proxy/beacon/IDiamondBeaconProxy.sol | 7 +++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 abi/IDiamondBeaconProxy.json create mode 100644 contracts/proxy/beacon/IDiamondBeaconProxy.sol diff --git a/abi/IDiamondBeaconProxy.json b/abi/IDiamondBeaconProxy.json new file mode 100644 index 00000000..7661f993 --- /dev/null +++ b/abi/IDiamondBeaconProxy.json @@ -0,0 +1,11 @@ +[ + { + "inputs": [], + "name": "Proxy__ImplementationIsNotContract", + "type": "error" + }, + { + "stateMutability": "payable", + "type": "fallback" + } +] diff --git a/contracts/proxy/beacon/DiamondBeaconProxy.sol b/contracts/proxy/beacon/DiamondBeaconProxy.sol index f2b95131..dc5ee949 100644 --- a/contracts/proxy/beacon/DiamondBeaconProxy.sol +++ b/contracts/proxy/beacon/DiamondBeaconProxy.sol @@ -4,8 +4,9 @@ pragma solidity ^0.8.18; import { BeaconProxy } from './BeaconProxy.sol'; import { IDiamondBeacon } from './IDiamondBeacon.sol'; +import { IDiamondBeaconProxy } from './IDiamondBeaconProxy.sol'; -abstract contract DiamondBeaconProxy is BeaconProxy { +abstract contract DiamondBeaconProxy is IDiamondBeaconProxy, BeaconProxy { function _getImplementation() internal view override returns (address) { return IDiamondBeacon(_getBeacon()).facetAddress(msg.sig); } diff --git a/contracts/proxy/beacon/IDiamondBeaconProxy.sol b/contracts/proxy/beacon/IDiamondBeaconProxy.sol new file mode 100644 index 00000000..f1774136 --- /dev/null +++ b/contracts/proxy/beacon/IDiamondBeaconProxy.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.18; + +import { IBeaconProxy } from './IBeaconProxy.sol'; + +interface IDiamondBeaconProxy is IBeaconProxy {} From 4790caa9cbe6b4cc2604c2fe15f1cb3156bb3c27 Mon Sep 17 00:00:00 2001 From: Nick Barry Date: Tue, 14 May 2024 01:59:00 +0400 Subject: [PATCH 10/10] update pragma statements for beacon contracts --- contracts/proxy/beacon/Beacon.sol | 2 +- contracts/proxy/beacon/BeaconInternal.sol | 2 +- contracts/proxy/beacon/BeaconProxy.sol | 2 +- contracts/proxy/beacon/BeaconProxyMock.sol | 2 +- contracts/proxy/beacon/BeaconStorage.sol | 2 +- contracts/proxy/beacon/DiamondBeacon.sol | 6 ++---- contracts/proxy/beacon/DiamondBeaconInternal.sol | 2 +- contracts/proxy/beacon/DiamondBeaconProxy.sol | 2 +- contracts/proxy/beacon/IBeacon.sol | 2 +- contracts/proxy/beacon/IBeaconInternal.sol | 2 +- contracts/proxy/beacon/IDiamondBeacon.sol | 2 +- contracts/proxy/beacon/IDiamondBeaconInternal.sol | 2 +- contracts/proxy/beacon/IDiamondBeaconProxy.sol | 2 +- 13 files changed, 14 insertions(+), 16 deletions(-) diff --git a/contracts/proxy/beacon/Beacon.sol b/contracts/proxy/beacon/Beacon.sol index 22439d8a..39c97090 100644 --- a/contracts/proxy/beacon/Beacon.sol +++ b/contracts/proxy/beacon/Beacon.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { Ownable } from '../../access/ownable/Ownable.sol'; import { IBeacon } from './IBeacon.sol'; diff --git a/contracts/proxy/beacon/BeaconInternal.sol b/contracts/proxy/beacon/BeaconInternal.sol index 89e25d30..f4072086 100644 --- a/contracts/proxy/beacon/BeaconInternal.sol +++ b/contracts/proxy/beacon/BeaconInternal.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { OwnableInternal } from '../../access/ownable/OwnableInternal.sol'; import { IBeaconInternal } from './IBeaconInternal.sol'; diff --git a/contracts/proxy/beacon/BeaconProxy.sol b/contracts/proxy/beacon/BeaconProxy.sol index f037f11c..86f4bf91 100644 --- a/contracts/proxy/beacon/BeaconProxy.sol +++ b/contracts/proxy/beacon/BeaconProxy.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { Proxy } from '../Proxy.sol'; import { IBeacon } from './IBeacon.sol'; diff --git a/contracts/proxy/beacon/BeaconProxyMock.sol b/contracts/proxy/beacon/BeaconProxyMock.sol index b18d6c81..f06155f8 100644 --- a/contracts/proxy/beacon/BeaconProxyMock.sol +++ b/contracts/proxy/beacon/BeaconProxyMock.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { BeaconProxy } from './BeaconProxy.sol'; diff --git a/contracts/proxy/beacon/BeaconStorage.sol b/contracts/proxy/beacon/BeaconStorage.sol index 3889d401..4f67cd3e 100644 --- a/contracts/proxy/beacon/BeaconStorage.sol +++ b/contracts/proxy/beacon/BeaconStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; library BeaconStorage { struct Layout { diff --git a/contracts/proxy/beacon/DiamondBeacon.sol b/contracts/proxy/beacon/DiamondBeacon.sol index abc1f4ee..711eb407 100644 --- a/contracts/proxy/beacon/DiamondBeacon.sol +++ b/contracts/proxy/beacon/DiamondBeacon.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { OwnableInternal } from '../../access/ownable/Ownable.sol'; import { Ownable } from '../../access/ownable/Ownable.sol'; @@ -19,6 +19,4 @@ contract DiamondBeacon is DiamondReadable, DiamondWritable, Ownable -{ - -} +{} diff --git a/contracts/proxy/beacon/DiamondBeaconInternal.sol b/contracts/proxy/beacon/DiamondBeaconInternal.sol index 864c0c3d..fbac4703 100644 --- a/contracts/proxy/beacon/DiamondBeaconInternal.sol +++ b/contracts/proxy/beacon/DiamondBeaconInternal.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { IDiamondBeaconInternal } from './IDiamondBeaconInternal.sol'; diff --git a/contracts/proxy/beacon/DiamondBeaconProxy.sol b/contracts/proxy/beacon/DiamondBeaconProxy.sol index dc5ee949..73267188 100644 --- a/contracts/proxy/beacon/DiamondBeaconProxy.sol +++ b/contracts/proxy/beacon/DiamondBeaconProxy.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { BeaconProxy } from './BeaconProxy.sol'; import { IDiamondBeacon } from './IDiamondBeacon.sol'; diff --git a/contracts/proxy/beacon/IBeacon.sol b/contracts/proxy/beacon/IBeacon.sol index 2f7cfe13..27b754df 100644 --- a/contracts/proxy/beacon/IBeacon.sol +++ b/contracts/proxy/beacon/IBeacon.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { IOwnable } from '../../access/ownable/IOwnable.sol'; import { BeaconStorage } from './BeaconStorage.sol'; diff --git a/contracts/proxy/beacon/IBeaconInternal.sol b/contracts/proxy/beacon/IBeaconInternal.sol index 31ed4b0b..1be4ee09 100644 --- a/contracts/proxy/beacon/IBeaconInternal.sol +++ b/contracts/proxy/beacon/IBeaconInternal.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { IOwnableInternal } from '../../access/ownable/IOwnableInternal.sol'; diff --git a/contracts/proxy/beacon/IDiamondBeacon.sol b/contracts/proxy/beacon/IDiamondBeacon.sol index 355a4d37..5241e636 100644 --- a/contracts/proxy/beacon/IDiamondBeacon.sol +++ b/contracts/proxy/beacon/IDiamondBeacon.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { IOwnable } from '../../access/ownable/IOwnable.sol'; import { IDiamondReadable } from '../diamond/readable/IDiamondReadable.sol'; diff --git a/contracts/proxy/beacon/IDiamondBeaconInternal.sol b/contracts/proxy/beacon/IDiamondBeaconInternal.sol index 0d1825dc..18d447fe 100644 --- a/contracts/proxy/beacon/IDiamondBeaconInternal.sol +++ b/contracts/proxy/beacon/IDiamondBeaconInternal.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { IBeaconInternal } from './IBeaconInternal.sol'; diff --git a/contracts/proxy/beacon/IDiamondBeaconProxy.sol b/contracts/proxy/beacon/IDiamondBeaconProxy.sol index f1774136..aff1e93f 100644 --- a/contracts/proxy/beacon/IDiamondBeaconProxy.sol +++ b/contracts/proxy/beacon/IDiamondBeaconProxy.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.20; import { IBeaconProxy } from './IBeaconProxy.sol';