Based on the Euler Finance tweet
by Michael Bentley
Unlike Uniswap v3 liquidity concentration with ranges, Uniswap v4 allows one to create unique invariants to offer a reduced price impact and to be able to also provide liquidity in the tails. A unique invariant that is between constant sum (x+y=k) and constant product (xy=k) is implemented as a hook based on the work of Michael Bentley utilizing the Lambert W function implemented with the solady fixdepointmath.sol library by vectorized.eth.
Screen.Recording.2024-03-01.at.11.18.27.PM.mov
- Default hook from Uniswap Foundation Counter.sol demonstrate the
beforeSwap()
hook where the invariant logic is inserted. - The invariant curve constant sum template used as our starting point Counter.t.sol preconfigures the v4 pool manager, test tokens, and test liquidity.
We solved the equation for swapping and removed c
the liquidity concentrationg parameter for the sake of simplicity (dashed line above):
![](https://private-user-images.githubusercontent.com/11951513/309447590-6d2b5f7c-55cf-48a2-b77f-a1e17652770b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQxNzExNzMsIm5iZiI6MTcyNDE3MDg3MywicGF0aCI6Ii8xMTk1MTUxMy8zMDk0NDc1OTAtNmQyYjVmN2MtNTVjZi00OGEyLWI3N2YtYTFlMTc2NTI3NzBiLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODIwVDE2MjExM1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI3M2EzYTJmNTI0ZDJmYzJlNDY4YzE0ZGYyOGJjZDExMWEwNjIwOGNjNDg0YzE3MmI2MzhhNDE1YTk1N2ZiYTAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.CcX4cWFTnivPC7yoDPzXbJDoIFMMxwauR_j5POr2D1U)
Though a more advanced hook could be to link c
to a ZK-coprocessor such as Axiom which would calculate volatility offchain and use that as a barometer. A high volatility would translate in c
moving the LAMMbert curve towards a constant product invariant and a low c
would move it towards a constant sum invariant.
An interesting combo we wanted to implement is to use Euler Vaults inside a beforeSwap()
for Just-in-Time liquidity provision, then move the gathered fees back into the Euler Vault.
Potential problem there would be changes in returning the same proportion of assets back as the LP composition changes though and we couldn't figure out how to return the same proportions that we borrowed.
requires foundry
forge install
forge test
add solady's fixedpointmath.sol library containing the Lambert W equation
forge install vectorized/solady
Other than writing unit tests (recommended!), you can only deploy & test hooks on anvil
# start anvil with TSTORE support
# (`foundryup`` to update if cancun is not an option)
anvil --hardfork cancun
# in a new terminal
forge script script/Anvil.s.sol \
--rpc-url http://localhost:8545 \
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
--broadcast
We ran out of time to test the invariant, only compiled it, but the Goerli deployment is out of sync with the latest v4. It is recommend to use local testing instead
POOL_MANAGER = 0x0
POOL_MODIFY_POSITION_TEST = 0x0
SWAP_ROUTER = 0x0
Update the following command with your own private key:
forge script script/00_Counter.s.sol \
--rpc-url https://rpc.ankr.com/eth_goerli \
--private-key [your_private_key_on_goerli_here] \
--broadcast
Because V4 is still in testing mode, most networks don't have liquidity pools live on V4 testnets. We recommend launching your own test tokens and expirementing with them that. We've included in the templace a Mock UNI and Mock USDC contract for easier testing. You can deploy the contracts and when you do you'll have 1 million mock tokens to test with for each contract. See deployment commands below
forge create script/mocks/mUNI.sol:MockUNI \
--rpc-url [your_rpc_url_here] \
--private-key [your_private_key_on_goerli_here]
forge create script/mocks/mUSDC.sol:MockUSDC \
--rpc-url [your_rpc_url_here] \
--private-key [your_private_key_on_goerli_here]
When installing dependencies with forge install
, Github may throw a Permission Denied
error
Typically caused by missing Github SSH keys, and can be resolved by following the steps here
Or adding the keys to your ssh-agent, if you have already uploaded SSH keys
Hook deployment failures are caused by incorrect flags or incorrect salt mining
- Verify the flags are in agreement:
getHookCalls()
returns the correct flagsflags
provided toHookMiner.find(...)
- Verify salt mining is correct:
- In forge test: the deployer for:
new Hook{salt: salt}(...)
andHookMiner.find(deployer, ...)
are the same. This will beaddress(this)
. If usingvm.prank
, the deployer will be the pranking address - In forge script: the deployer must be the CREATE2 Proxy:
0x4e59b44847b379578588920cA78FbF26c0B4956C
- If anvil does not have the CREATE2 deployer, your foundry may be out of date. You can update it with
foundryup
- If anvil does not have the CREATE2 deployer, your foundry may be out of date. You can update it with
- In forge test: the deployer for: