From 7a1dfad17186e6fe676fbd9dc239d537cc5a23b2 Mon Sep 17 00:00:00 2001 From: 0xwalid Date: Thu, 30 May 2024 20:02:41 -0700 Subject: [PATCH] change proxy storage pattern --- script/DeployL2XPufETH.s.sol | 35 ++++++++---- src/l2/XERC20PufferVault.sol | 84 ++++++++++++++++------------- src/l2/XERC20PufferVaultStorage.sol | 40 ++++++++++++++ 3 files changed, 111 insertions(+), 48 deletions(-) create mode 100644 src/l2/XERC20PufferVaultStorage.sol diff --git a/script/DeployL2XPufETH.s.sol b/script/DeployL2XPufETH.s.sol index f2e4a04..451c4b6 100644 --- a/script/DeployL2XPufETH.s.sol +++ b/script/DeployL2XPufETH.s.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import "forge-std/Script.sol"; import { stdJson } from "forge-std/StdJson.sol"; import { BaseScript } from ".//BaseScript.s.sol"; import { XERC20PufferVault } from "../src/l2/XERC20PufferVault.sol"; import { UUPSUpgradeable } from "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import { Initializable } from "openzeppelin/proxy/utils/Initializable.sol"; -import { NoImplementation } from "../src/NoImplementation.sol"; import { Timelock } from "../src/Timelock.sol"; import { ERC1967Proxy } from "openzeppelin/proxy/ERC1967/ERC1967Proxy.sol"; import { AccessManager } from "openzeppelin/access/manager/AccessManager.sol"; @@ -33,31 +33,46 @@ contract DeployL2XPufETH is BaseScript { address pauserMultisig = vm.envOr("PAUSER_MULTISIG", makeAddr("pauserMultisig")); address communityMultisig = vm.envOr("COMMUNITY_MULTISIG", makeAddr("communityMultisig")); + address _CONNEXT = 0x8247ed6d0a344eeae4edBC7e44572F1B70ECA82A; // change for mainnet + uint256 _MINTING_LIMIT = 1000 * 1e18; + uint256 _BURNING_LIMIT = 1000 * 1e18; + function run() public broadcast { AccessManager accessManager = new AccessManager(_broadcaster); + console.log("AccessManager", address(accessManager)); + + operationsMultisig = _broadcaster; + pauserMultisig = _broadcaster; + communityMultisig = _broadcaster; + Timelock timelock = new Timelock({ accessManager: address(accessManager), communityMultisig: communityMultisig, operationsMultisig: operationsMultisig, pauser: pauserMultisig, - initialDelay: 7 days + 1 + initialDelay: 7 days }); - address noImpl = address(new NoImplementation()); + console.log("AccessManager", address(timelock)); - bytes32 xPufETHSalt = bytes32("xPufETH"); + XERC20PufferVault newImplementation = new XERC20PufferVault(); + console.log("XERC20PufferVault", address(newImplementation)); - ERC1967Proxy xPufETH = new ERC1967Proxy{ salt: xPufETHSalt }(noImpl, ""); - vm.label(address(xPufETH), "xPufETH"); + bytes32 xPufETHSalt = bytes32("xPufETH"); - XERC20PufferVault newImplementation = new XERC20PufferVault(); + ERC1967Proxy xPufETH = new ERC1967Proxy{ salt: xPufETHSalt }( + address(newImplementation), abi.encodeCall(XERC20PufferVault.initialize, (address(accessManager))) + ); + console.log("xPufETHProxy", address(xPufETH)); vm.expectEmit(true, true, true, true); emit Initializable.Initialized(1); - NoImplementation(payable(address(xPufETH))).upgradeToAndCall( - address(newImplementation), abi.encodeCall(XERC20PufferVault.initialize, (address(accessManager))) - ); + + bytes memory data = + abi.encodeWithSelector(XERC20PufferVault.setLimits.selector, _CONNEXT, _MINTING_LIMIT, _BURNING_LIMIT); + + accessManager.execute(address(xPufETH), data); bytes4[] memory selectors = new bytes4[](2); selectors[0] = XERC20PufferVault.setLockbox.selector; diff --git a/src/l2/XERC20PufferVault.sol b/src/l2/XERC20PufferVault.sol index e06a9b9..2fb92a4 100644 --- a/src/l2/XERC20PufferVault.sol +++ b/src/l2/XERC20PufferVault.sol @@ -7,23 +7,20 @@ import { AccessManagedUpgradeable } from "@openzeppelin-contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; import { ERC20PermitUpgradeable } from "@openzeppelin-contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol"; +import { XERC20PufferVaultStorage } from "./XERC20PufferVaultStorage.sol"; -contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgradeable, UUPSUpgradeable { +contract XERC20PufferVault is + XERC20PufferVaultStorage, + IXERC20, + AccessManagedUpgradeable, + ERC20PermitUpgradeable, + UUPSUpgradeable +{ /** * @notice The duration it takes for the limits to fully replenish */ uint256 private constant _DURATION = 1 days; - /** - * @notice The address of the lockbox contract - */ - address public lockbox; - - /** - * @notice Maps bridge address to bridge configurations - */ - mapping(address => Bridge) public bridges; - constructor() { _disableInitializers(); } @@ -64,7 +61,8 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @param lockboxAddress The address of the lockbox */ function setLockbox(address lockboxAddress) public restricted { - lockbox = lockboxAddress; + VaultStorage storage $ = _getPufferVaultStorage(); + $.lockbox = lockboxAddress; emit LockboxSet(lockboxAddress); } @@ -93,7 +91,8 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @return limit The limit the bridge has */ function mintingMaxLimitOf(address bridge) public view returns (uint256 limit) { - limit = bridges[bridge].minterParams.maxLimit; + VaultStorage storage $ = _getPufferVaultStorage(); + limit = $.bridges[bridge].minterParams.maxLimit; } /** @@ -103,7 +102,8 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @return limit The limit the bridge has */ function burningMaxLimitOf(address bridge) public view returns (uint256 limit) { - limit = bridges[bridge].burnerParams.maxLimit; + VaultStorage storage $ = _getPufferVaultStorage(); + limit = $.bridges[bridge].burnerParams.maxLimit; } /** @@ -113,11 +113,12 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @return limit The limit the bridge has */ function mintingCurrentLimitOf(address bridge) public view returns (uint256 limit) { + VaultStorage storage $ = _getPufferVaultStorage(); limit = _getCurrentLimit( - bridges[bridge].minterParams.currentLimit, - bridges[bridge].minterParams.maxLimit, - bridges[bridge].minterParams.timestamp, - bridges[bridge].minterParams.ratePerSecond + $.bridges[bridge].minterParams.currentLimit, + $.bridges[bridge].minterParams.maxLimit, + $.bridges[bridge].minterParams.timestamp, + $.bridges[bridge].minterParams.ratePerSecond ); } @@ -128,11 +129,12 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @return limit The limit the bridge has */ function burningCurrentLimitOf(address bridge) public view returns (uint256 limit) { + VaultStorage storage $ = _getPufferVaultStorage(); limit = _getCurrentLimit( - bridges[bridge].burnerParams.currentLimit, - bridges[bridge].burnerParams.maxLimit, - bridges[bridge].burnerParams.timestamp, - bridges[bridge].burnerParams.ratePerSecond + $.bridges[bridge].burnerParams.currentLimit, + $.bridges[bridge].burnerParams.maxLimit, + $.bridges[bridge].burnerParams.timestamp, + $.bridges[bridge].burnerParams.ratePerSecond ); } @@ -142,9 +144,10 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @param change The change in the limit */ function _useMinterLimits(address bridge, uint256 change) internal { + VaultStorage storage $ = _getPufferVaultStorage(); uint256 currentLimit = mintingCurrentLimitOf(bridge); - bridges[bridge].minterParams.timestamp = block.timestamp; - bridges[bridge].minterParams.currentLimit = currentLimit - change; + $.bridges[bridge].minterParams.timestamp = block.timestamp; + $.bridges[bridge].minterParams.currentLimit = currentLimit - change; } /** @@ -153,9 +156,10 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @param change The change in the limit */ function _useBurnerLimits(address bridge, uint256 change) internal { + VaultStorage storage $ = _getPufferVaultStorage(); uint256 currentLimit = burningCurrentLimitOf(bridge); - bridges[bridge].burnerParams.timestamp = block.timestamp; - bridges[bridge].burnerParams.currentLimit = currentLimit - change; + $.bridges[bridge].burnerParams.timestamp = block.timestamp; + $.bridges[bridge].burnerParams.currentLimit = currentLimit - change; } /** @@ -165,14 +169,15 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @param limit The updated limit we are setting to the bridge */ function _changeMinterLimit(address bridge, uint256 limit) internal { - uint256 oldLimit = bridges[bridge].minterParams.maxLimit; + VaultStorage storage $ = _getPufferVaultStorage(); + uint256 oldLimit = $.bridges[bridge].minterParams.maxLimit; uint256 currentLimit = mintingCurrentLimitOf(bridge); - bridges[bridge].minterParams.maxLimit = limit; + $.bridges[bridge].minterParams.maxLimit = limit; - bridges[bridge].minterParams.currentLimit = _calculateNewCurrentLimit(limit, oldLimit, currentLimit); + $.bridges[bridge].minterParams.currentLimit = _calculateNewCurrentLimit(limit, oldLimit, currentLimit); - bridges[bridge].minterParams.ratePerSecond = limit / _DURATION; - bridges[bridge].minterParams.timestamp = block.timestamp; + $.bridges[bridge].minterParams.ratePerSecond = limit / _DURATION; + $.bridges[bridge].minterParams.timestamp = block.timestamp; } /** @@ -182,14 +187,15 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @param limit The updated limit we are setting to the bridge */ function _changeBurnerLimit(address bridge, uint256 limit) internal { - uint256 oldLimit = bridges[bridge].burnerParams.maxLimit; + VaultStorage storage $ = _getPufferVaultStorage(); + uint256 oldLimit = $.bridges[bridge].burnerParams.maxLimit; uint256 currentLimit = burningCurrentLimitOf(bridge); - bridges[bridge].burnerParams.maxLimit = limit; + $.bridges[bridge].burnerParams.maxLimit = limit; - bridges[bridge].burnerParams.currentLimit = _calculateNewCurrentLimit(limit, oldLimit, currentLimit); + $.bridges[bridge].burnerParams.currentLimit = _calculateNewCurrentLimit(limit, oldLimit, currentLimit); - bridges[bridge].burnerParams.ratePerSecond = limit / _DURATION; - bridges[bridge].burnerParams.timestamp = block.timestamp; + $.bridges[bridge].burnerParams.ratePerSecond = limit / _DURATION; + $.bridges[bridge].burnerParams.timestamp = block.timestamp; } /** @@ -250,7 +256,8 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @param amount The amount to burn */ function _burnWithCaller(address caller, address user, uint256 amount) internal { - if (caller != lockbox) { + VaultStorage storage $ = _getPufferVaultStorage(); + if (caller != $.lockbox) { uint256 currentLimit = burningCurrentLimitOf(caller); if (currentLimit < amount) revert IXERC20_NotHighEnoughLimits(); _useBurnerLimits(caller, amount); @@ -266,7 +273,8 @@ contract XERC20PufferVault is IXERC20, AccessManagedUpgradeable, ERC20PermitUpgr * @param amount The amount to mint */ function _mintWithCaller(address caller, address user, uint256 amount) internal { - if (caller != lockbox) { + VaultStorage storage $ = _getPufferVaultStorage(); + if (caller != $.lockbox) { uint256 currentLimit = mintingCurrentLimitOf(caller); if (currentLimit < amount) revert IXERC20_NotHighEnoughLimits(); _useMinterLimits(caller, amount); diff --git a/src/l2/XERC20PufferVaultStorage.sol b/src/l2/XERC20PufferVaultStorage.sol new file mode 100644 index 0000000..3571af5 --- /dev/null +++ b/src/l2/XERC20PufferVaultStorage.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import { IXERC20 } from "./interface/IXERC20.sol"; + +/** + * @title XERC20PufferVaultStorage + * @author Puffer Finance + */ +abstract contract XERC20PufferVaultStorage { + /** + * @custom:storage-location erc7201:puffervault.storage + * @dev +-----------------------------------------------------------+ + * | | + * | DO NOT CHANGE, REORDER, REMOVE EXISTING STORAGE VARIABLES | + * | | + * +-----------------------------------------------------------+ + */ + struct VaultStorage { + /** + * @notice The address of the lockbox contract + */ + address lockbox; + /** + * @notice Maps bridge address to bridge configurations + */ + mapping(address => IXERC20.Bridge) bridges; + } + + // keccak256(abi.encode(uint256(keccak256("puffervault.storage")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant _VAULT_STORAGE_LOCATION = + 0x611ea165ca9257827fc43d2954fdae7d825e82c825d9037db9337fa1bfa93100; + + function _getPufferVaultStorage() internal pure returns (VaultStorage storage $) { + // solhint-disable-next-line no-inline-assembly + assembly { + $.slot := _VAULT_STORAGE_LOCATION + } + } +}