Skip to content

Commit

Permalink
Readme
Browse files Browse the repository at this point in the history
  • Loading branch information
scab24 committed Sep 18, 2024
1 parent 280b6be commit 3c41984
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 101 deletions.
103 changes: 59 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,81 @@
## Uniswap v4 Risk Neutral Hook
# UniswapV4 - Risk Neutral Hook

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**

Foundry consists of:
<div style="margin: 20px 0;">
<img alt="image" src="UniV4.png" style="width: 100%; height: auto;">
</div>

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.
[This is the explanatory video for our Hook](https://youtu.be/_3UwdIoU23w)

## Documentation
[You can also view the presentation slides here](https://docs.google.com/presentation/d/1V69IXV7AJSI59UxeSnM4UYf7mCy2Leu2MyUha8utA2M/edit#slide=id.g2d31d7c8c7b_7_58)

https://book.getfoundry.sh/
We try to provide a combined solution to hedge **IL** & **LVR** via dynamic fees and hedges to achieve both delta and gamma neutrality.

## Usage
### Background

### Build
When providing liquidity to Uniswap, liquidity providers (LPs) are subject to the price mechanics of the constant function formula:

```shell
$ forge build
```
**x * y = k**

### Test
Due to LP positions having negative convexity (which can be proven using Jensen's Inequality), the value of the position will always be inferior to simply holding the tokens (without accounting for fees).

```shell
$ forge test
```
### Quantifying LP Losses

### Format
There are two main methods of quantifying the loss LPs incur:

```shell
$ forge fmt
```
- **Loss-Versus-HODLing**: Also known as Impermanent or Divergence Loss.
- **Loss-Versus-Rebalancing**: Also known as "lever."

### Gas Snapshots
While Impermanent Loss has been the primary metric for quantifying LP losses on Uniswap, it has some major drawbacks:

```shell
$ forge snapshot
```
- It compares LP value to the value of simply holding the tokens, which is an unrealistic strategy.
- If the price diverges and then returns to the original price, IL=0, completely disregarding volatility.

### Anvil
Conversely, "lever" is path-dependent, taking into account rebalancing (and arbitrage) opportunities given a time series of prices. It occurs mainly due to AMMs having "stale" prices.

```shell
$ anvil
```
Moreover, it has been proven that LPs have underpriced volatility and therefore market risk, foregoing additional profits and having a negative Volatility Risk Premium. This can be demonstrated by deriving implied volatility from Uniswap positions and comparing it to realized volatility from any liquid market where price discovery is supposed to occur, such as Deribit.

### Deploy
### Reducing LP Losses

```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```
Given that an LP has already chosen a pool, there are two main ways of reducing these losses:

### Cast
- **Using hedges**
- **Dynamically modifying pool fees**

```shell
$ cast <subcommand>
```
---

### Help
## Hedges

```shell
$ forge --help
$ anvil --help
$ cast --help
```
Due to the negative convexity of the LP value function, their positions cannot be hedged solely with delta-one or linear products. However, for small price movements, a delta-hedge can be sufficient to offset "lever." This can be achieved either by:

- Selling futures
- On-chain borrowing and setting a rebalance threshold, from which, if surpassed, a re-hedge is executed.

For LPs desiring a complete hedge to offset all directional risk, products like power perpetuals or options are the preferred approach.

We implement a basic Proof of Concept (PoC) of how LP Greeks are updated and how this can be used to compute any hedging updates, verifying that the position is correctly hedged.

---

## Dynamic Fees

To correctly remunerate LPs and price volatility accordingly, as well as reduce price impact for large swaps and account for market conditions via gas price, a dynamic fee system has been implemented.

To achieve this, we extract the implied volatility of the pool from volatile asset drift and the return from pool fees using the formula derived by **Daniel Alcarraz**.

We attempted to devise a simple model that dynamically adjusts the fees with a discount factor based on the **Volatility Risk Premium**—that is, the difference between Implied and Realised Volatility.

- **Whenever implied volatility is higher** than historical or expected volatility, providing liquidity yields a positive expected return.

- **If the implied volatility is lower**, the return becomes negative.

> *“If the implied volatility is lower than the historical or expected volatility, the return becomes negative.”* - Daniel Alcarraz
We are also currently investigating the Implied Volatility formula proposed by **Guillaume Lambert**. There is significant room for improvement in both the parameters and the formulas.

These are preliminary implementations to have the Proof-of-Concept ready for the hackathon but will likely change in the following weeks. We will also be performing:

- A backend (taking care to avoid backtesting overfitting)
- A forward test of the models
- Unit, integration, and fuzz tests
- Formal verification of all the code
Binary file added Univ4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
114 changes: 57 additions & 57 deletions test/univ4-risk-neutral-hook.t.sol
Original file line number Diff line number Diff line change
@@ -1,68 +1,68 @@
// // SPDX-License-Identifier: MIT
// pragma solidity ^0.8.0;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// import {Test} from "forge-std/Test.sol";
// import {Deployers} from "@uniswap/v4-core/test/utils/Deployers.sol";
// import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol";
// import {PoolManager} from "v4-core/PoolManager.sol";
// import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol";
// import {Currency, CurrencyLibrary} from "v4-core/types/Currency.sol";
// import {PoolId, PoolIdLibrary} from "v4-core/types/PoolId.sol";
// import {LPFeeLibrary} from "v4-core/libraries/LPFeeLibrary.sol";
// import {PoolKey} from "v4-core/types/PoolKey.sol";
// import {Hooks} from "v4-core/libraries/Hooks.sol";
// import {PoolSwapTest} from "v4-core/test/PoolSwapTest.sol";
// import {univ4-risk-neutral-hook} from "../src/GasPriceFeesHook.sol";
// import {TickMath} from "v4-core/libraries/TickMath.sol";
// import {console} from "forge-std/console.sol";
import {Test} from "forge-std/Test.sol";
import {Deployers} from "@uniswap/v4-core/test/utils/Deployers.sol";
import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol";
import {PoolManager} from "v4-core/PoolManager.sol";
import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol";
import {Currency, CurrencyLibrary} from "v4-core/types/Currency.sol";
import {PoolId, PoolIdLibrary} from "v4-core/types/PoolId.sol";
import {LPFeeLibrary} from "v4-core/libraries/LPFeeLibrary.sol";
import {PoolKey} from "v4-core/types/PoolKey.sol";
import {Hooks} from "v4-core/libraries/Hooks.sol";
import {PoolSwapTest} from "v4-core/test/PoolSwapTest.sol";
import {univ4riskneutralhook} from "../src/Hook/univ4-risk-neutral-hook.sol";
import {TickMath} from "v4-core/libraries/TickMath.sol";
import {console} from "forge-std/console.sol";

// contract univ4riskneutralhookTest is Test, Deployers {
// using CurrencyLibrary for Currency;
// using PoolIdLibrary for PoolKey;
contract univ4riskneutralhookTest is Test, Deployers {
using CurrencyLibrary for Currency;
using PoolIdLibrary for PoolKey;

// GasPriceFeesHook hook;
univ4riskneutralhook hook;

// function setUp() public {
// // Deploy v4-core
// deployFreshManagerAndRouters();
function setUp() public {
// Deploy v4-core
deployFreshManagerAndRouters();

// // Deploy, mint tokens, and approve all periphery contracts for two tokens
// deployMintAndApprove2Currencies();
// Deploy, mint tokens, and approve all periphery contracts for two tokens
deployMintAndApprove2Currencies();

// // Deploy our hook with the proper flags
// address hookAddress = address(
// uint160(
// Hooks.BEFORE_INITIALIZE_FLAG |
// Hooks.BEFORE_SWAP_FLAG |
// Hooks.AFTER_SWAP_FLAG
// )
// );
// Deploy our hook with the proper flags
address hookAddress = address(
uint160(
Hooks.BEFORE_INITIALIZE_FLAG |
Hooks.BEFORE_SWAP_FLAG |
Hooks.AFTER_SWAP_FLAG
)
);

// vm.txGasPrice(10 gwei);
// deployCodeTo("GasPriceFeesHook", abi.encode(manager), hookAddress);
// hook = GasPriceFeesHook(hookAddress);
vm.txGasPrice(10 gwei);
deployCodeTo("univ4riskneutralhook", abi.encode(manager), hookAddress);
hook = univ4riskneutralhook(hookAddress);

// // Initialize a pool
// (key, ) = initPool(
// currency0,
// currency1,
// hook,
// LPFeeLibrary.DYNAMIC_FEE_FLAG, // Set the `DYNAMIC_FEE_FLAG` in place of specifying a fixed fee
// SQRT_PRICE_1_1,
// ZERO_BYTES
// );
// Initialize a pool
(key, ) = initPool(
currency0,
currency1,
hook,
LPFeeLibrary.DYNAMIC_FEE_FLAG, // Set the `DYNAMIC_FEE_FLAG` in place of specifying a fixed fee
SQRT_PRICE_1_1,
ZERO_BYTES
);

// modifyLiquidityRouter.modifyLiquidity(
// key,
// IPoolManager.ModifyLiquidityParams({
// tickLower: -60,
// tickUpper: 60,
// liquidityDelta: 100 ether,
// salt: bytes32(0)
// }),
// ZERO_BYTES
// );
// }
modifyLiquidityRouter.modifyLiquidity(
key,
IPoolManager.ModifyLiquidityParams({
tickLower: -60,
tickUpper: 60,
liquidityDelta: 100 ether,
salt: bytes32(0)
}),
ZERO_BYTES
);
}


// }
}

0 comments on commit 3c41984

Please sign in to comment.