Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@uniswap/v4-core/=lib/v4-core/
v4-core/=lib/v4-core/
v4-periphery/=lib/v4-periphery/
v4-periphery/=lib/v4-periphery/
v4-periphery/=lib/v4-periphery/
openzeppelin-contracts/=lib/v4-core/lib/openzeppelin-contracts/contracts/
40 changes: 26 additions & 14 deletions script/deployPoolWithRenzoStability.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {SqrtPriceLibrary} from "../src/libraries/SqrtPriceLibrary.sol";
import {LPFeeLibrary} from "v4-core/src/libraries/LPFeeLibrary.sol";
import {IRateProvider} from "../src/interfaces/IRateProvider.sol";
import {PoolId} from "v4-core/src/types/PoolId.sol";

import {TransparentUpgradeableProxy} from "openzeppelin-contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {Constants} from "./sepolia/Constants.sol";
import {Config} from "./sepolia/Config.sol";

Expand All @@ -26,44 +26,56 @@ contract RenzoStabilityScript is Script, Constants, Config {
uint24 minFee = 100;
uint24 maxFee = 10_000;
address ezETH = 0x8d7F20137041334FBd7c87796f03b1999770Cc5f;
address proxyAdmin = 0x91625601e2BbBEb7171C40c79FadBCFbFf6A1982;

// Pool configs
// TODO: configure 0 zero values
int24 tickSpacing = 60;
uint160 startingPrice; // starting price in sqrtPriceX96

function run() public {
// Deploy the hook implementation
RenzoStability renzoStabilityImpl = new RenzoStability(POOLMANAGER);

bytes memory initData = abi.encodeWithSelector(
RenzoStability.initialize.selector,
rateProvider,
minFee,
maxFee,
ezETH
);

// hook contracts must have specific flags encoded in the address
uint160 flags = uint160(
Hooks.AFTER_INITIALIZE_FLAG | Hooks.BEFORE_SWAP_FLAG
);

// Mine a salt that will produce a hook address with the correct flags
bytes memory constructorArgs = abi.encode(
POOLMANAGER,
rateProvider,
minFee,
maxFee,
ezETH
address(renzoStabilityImpl),
proxyAdmin,
initData
);
(address hookAddress, bytes32 salt) = HookMiner.find(
CREATE2_FACTORY,
flags,
type(RenzoStability).creationCode,
type(TransparentUpgradeableProxy).creationCode,
constructorArgs
);

startingPrice = SqrtPriceLibrary.exchangeRateToSqrtPriceX96(
rateProvider.getRate()
);
// Deploy the hook using CREATE2
// Deploy the hook proxy using CREATE2
vm.startBroadcast();
RenzoStability renzoStability = new RenzoStability{salt: salt}(
POOLMANAGER,
rateProvider,
minFee,
maxFee,
ezETH
RenzoStability renzoStability = RenzoStability(
address(
new TransparentUpgradeableProxy{salt: salt}(
address(renzoStabilityImpl),
proxyAdmin,
initData
)
)
);
require(
address(renzoStability) == hookAddress,
Expand Down
38 changes: 26 additions & 12 deletions script/deployPoolWithRenzoStabilityAndMintLiquidity.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {Constants} from "./unichain/Constants.sol";
import {PoolId} from "v4-core/src/types/PoolId.sol";
import {Config} from "./unichain/Config.sol";
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
import {TransparentUpgradeableProxy} from "openzeppelin-contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

contract CreatePoolAndAddLiquidityScript is Script, Constants, Config {
using CurrencyLibrary for Currency;
Expand All @@ -37,6 +38,7 @@ contract CreatePoolAndAddLiquidityScript is Script, Constants, Config {
uint24 minFee = 100;
uint24 maxFee = 10_000;
address ezETH = 0x2416092f143378750bb29b79eD961ab195CcEea5;
address proxyAdmin = 0x91625601e2BbBEb7171C40c79FadBCFbFf6A1982;
address payable recipient =
payable(0xAdef586efB3287Da4d7d1cbe15F12E0Be69e0DF0);

Expand Down Expand Up @@ -145,23 +147,33 @@ contract CreatePoolAndAddLiquidityScript is Script, Constants, Config {
}

function _deployHook() internal returns (address) {
// Deploy the hook implementation
RenzoStability renzoStabilityImpl = new RenzoStability(POOLMANAGER);

// Initialize data for the hook
bytes memory initData = abi.encodeWithSelector(
RenzoStability.initialize.selector,
rateProvider,
minFee,
maxFee,
ezETH
);

// hook contracts must have specific flags encoded in the address
uint160 flags = uint160(
Hooks.AFTER_INITIALIZE_FLAG | Hooks.BEFORE_SWAP_FLAG
);

// Mine a salt that will produce a hook address with the correct flags
bytes memory constructorArgs = abi.encode(
POOLMANAGER,
rateProvider,
minFee,
maxFee,
ezETH
address(renzoStabilityImpl),
proxyAdmin,
initData
);
(address hookAddress, bytes32 salt) = HookMiner.find(
CREATE2_DEPLOYER,
flags,
type(RenzoStability).creationCode,
type(TransparentUpgradeableProxy).creationCode,
constructorArgs
);

Expand All @@ -170,12 +182,14 @@ contract CreatePoolAndAddLiquidityScript is Script, Constants, Config {
);
// Deploy the hook using CREATE2
vm.startBroadcast();
RenzoStability renzoStability = new RenzoStability{salt: salt}(
POOLMANAGER,
rateProvider,
minFee,
maxFee,
ezETH
RenzoStability renzoStability = RenzoStability(
address(
new TransparentUpgradeableProxy{salt: salt}(
address(renzoStabilityImpl),
proxyAdmin,
initData
)
)
);
vm.stopBroadcast();
// check that the hook was deployed at the expected address
Expand Down
26 changes: 14 additions & 12 deletions src/RenzoStability.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,27 @@ import {PoolKey} from "v4-core/src/types/PoolKey.sol";
import {Currency} from "v4-core/src/types/Currency.sol";
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
import {SqrtPriceLibrary} from "./libraries/SqrtPriceLibrary.sol";
import {IRateProvider} from "./interfaces/IRateProvider.sol";
import {LPFeeLibrary} from "v4-core/src/libraries/LPFeeLibrary.sol";
import {Initializable} from "openzeppelin-contracts/proxy/utils/Initializable.sol";
import "./RenzoStabilityStorage.sol";

/// @title RenzoStability
/// @notice A peg stability hook, for pairs that trade at a 1:1 ratio
/// The hook charges 1 bip for trades moving towards the peg
/// otherwise it charges a linearly-scaled fee based on the distance from the peg
/// i.e. if the pool price is off by 0.05% the fee is 0.05%, if the price is off by 0.50% the fee is 0.5%
/// In the associated pool, Token 0 should be ETH and Token 1 should be ezETH
contract RenzoStability is PegStabilityHook {
contract RenzoStability is
PegStabilityHook,
Initializable,
RenzoStabilityStorageV1
{
using LPFeeLibrary for uint24;

IRateProvider public immutable rateProvider;

// Fee bps range where 1_000_000 = 100 %
uint24 public constant MAX_FEE_BPS = 10_000; // 1% max fee allowed, 1% = 10_000
uint24 public constant MIN_FEE_BPS = 100; // 0.01% mix fee allowed

uint24 public immutable maxFeeBps;
uint24 public immutable minFeeBps;

address public immutable ezETH;

// Errors
// @dev error when Invalid zero input params
error InvalidZeroInput();
Expand All @@ -44,13 +42,17 @@ contract RenzoStability is PegStabilityHook {
/// @dev Error when Invalid Currency in Pool
error InvalidPoolCurrency();

constructor(
IPoolManager _poolManager,
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(IPoolManager _poolManager) PegStabilityHook(_poolManager) {
_disableInitializers();
}

function initialize(
IRateProvider _rateProvider,
uint24 _minFee,
uint24 _maxFee,
address _ezETH
) PegStabilityHook(_poolManager) {
) public initializer {
// check for 0 value inputs
if (
address(_rateProvider) == address(0) ||
Expand Down
14 changes: 14 additions & 0 deletions src/RenzoStabilityStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IRateProvider} from "./interfaces/IRateProvider.sol";

abstract contract RenzoStabilityStorageV1 {
IRateProvider public rateProvider;

uint24 public maxFeeBps;

uint24 public minFeeBps;

address public ezETH;
}
27 changes: 21 additions & 6 deletions test/RenzoStability.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ import {IRateProvider} from "../src/interfaces/IRateProvider.sol";
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
import {SwapFeeEventAsserter} from "./utils/SwapFeeEventAsserter.sol";
import {SqrtPriceLibrary} from "../src/libraries/SqrtPriceLibrary.sol";
import {TransparentUpgradeableProxy, ProxyAdmin} from "openzeppelin-contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

contract RenzoStabilityTest is Deployers {
address owner = makeAddr("owner");
// Hook configs. TODO: configure
IRateProvider rateProvider = IRateProvider(makeAddr("rateProvider"));

uint256 exchangeRate = 1046726277868365115;
uint24 minFee = 100;
uint24 maxFee = 10_000;
Expand All @@ -51,20 +54,32 @@ contract RenzoStabilityTest is Deployers {

vm.deal(address(this), 1_000_000e18);

// Deploy ProxyAdmin
ProxyAdmin proxyAdmin = new ProxyAdmin(owner);

// Deploy the hook implementation
RenzoStability renzoStabilityImpl = new RenzoStability(manager);

bytes memory initData = abi.encodeWithSelector(
RenzoStability.initialize.selector,
rateProvider,
minFee,
maxFee,
Currency.unwrap(currency1)
);

// Deploy the hook to an address with the correct flags
address flags = address(
uint160(Hooks.AFTER_INITIALIZE_FLAG | Hooks.BEFORE_SWAP_FLAG) ^
(0x4444 << 144) // Namespace the hook to avoid collisions
);
bytes memory constructorArgs = abi.encode(
manager,
rateProvider,
minFee,
maxFee,
Currency.unwrap(currency1)
address(renzoStabilityImpl),
address(proxyAdmin),
initData
); //Add all the necessary constructor arguments from the hook
deployCodeTo(
"RenzoStability.sol:RenzoStability",
"openzeppelin-contracts/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy",
constructorArgs,
flags
);
Expand Down