Skip to content

Commit

Permalink
change proxy storage pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
WalidOfNow committed May 31, 2024
1 parent 0efb224 commit 7a1dfad
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 48 deletions.
35 changes: 25 additions & 10 deletions script/DeployL2XPufETH.s.sol
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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;
Expand Down
84 changes: 46 additions & 38 deletions src/l2/XERC20PufferVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -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;
}

/**
Expand All @@ -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
);
}

Expand All @@ -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
);
}

Expand All @@ -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;
}

/**
Expand All @@ -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;
}

/**
Expand All @@ -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;
}

/**
Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
40 changes: 40 additions & 0 deletions src/l2/XERC20PufferVaultStorage.sol
Original file line number Diff line number Diff line change
@@ -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
}
}
}

0 comments on commit 7a1dfad

Please sign in to comment.