This guide explains how to successfully create EulerSwap pools with Uniswap v4 integration.
./deploy-scenario.sh EulerSwapPoolCreationThis scenario automatically:
- Deploys USDC and USDT vaults with liquidity
- Mines a valid salt using HookMiner
- Creates the pool successfully
forge script script/MineSaltForPool.s.sol --rpc-url http://localhost:8545Configure with environment variables:
VAULT0: First vault addressVAULT1: Second vault addressEULER_ACCOUNT: Account that will own the poolFACTORY: EulerSwapFactory addressIMPL: EulerSwap implementation address
EulerSwap pools act as hooks for Uniswap v4. Uniswap v4 requires hook addresses to have specific permission bits encoded in their address. This presents a challenge because EulerSwap uses MetaProxy deployment, which means the actual pool address must have the correct permission bits.
The solution is to use the HookMiner utility from the EulerSwap test suite to find a salt that produces a valid hook address.
-
Define Pool Parameters: Set up your pool configuration (vaults, reserves, fees, etc.)
-
Calculate Required Flags: EulerSwap pools need these permission flags:
BEFORE_INITIALIZE_FLAGBEFORE_SWAP_FLAGBEFORE_SWAP_RETURNS_DELTA_FLAGBEFORE_DONATE_FLAGBEFORE_ADD_LIQUIDITY_FLAG
-
Mine Salt: Use HookMiner to find a salt that produces an address with the correct permission bits:
bytes memory creationCode = MetaProxyDeployer.creationCodeMetaProxy(eulerSwapImpl, abi.encode(poolParams)); (address hookAddress, bytes32 salt) = HookMiner.find(address(eulerSwapFactory), flags, creationCode);
-
Deploy Pool: Use the mined salt in your deployment through EVC batch
// Mine salt
uint160 flags = uint160(
Hooks.BEFORE_INITIALIZE_FLAG |
Hooks.BEFORE_SWAP_FLAG |
Hooks.BEFORE_SWAP_RETURNS_DELTA_FLAG |
Hooks.BEFORE_DONATE_FLAG |
Hooks.BEFORE_ADD_LIQUIDITY_FLAG
);
bytes memory creationCode = MetaProxyDeployer.creationCodeMetaProxy(eulerSwapImpl, abi.encode(poolParams));
(address hookAddress, bytes32 salt) = HookMiner.find(address(eulerSwapFactory), flags, creationCode);
// Deploy pool via EVC
IEVC.BatchItem[] memory items = new IEVC.BatchItem[](2);
items[0] = IEVC.BatchItem({
onBehalfOfAccount: address(0),
targetContract: address(evc),
value: 0,
data: abi.encodeCall(evc.setAccountOperator, (user0, hookAddress, true))
});
items[1] = IEVC.BatchItem({
onBehalfOfAccount: user0,
targetContract: address(eulerSwapFactory),
value: 0,
data: abi.encodeCall(IEulerSwapFactory.deployPool, (poolParams, initialState, salt))
});
evc.batch(items);-
Salt is Pool-Specific: The salt depends on the exact pool parameters. If you change any parameter (vaults, reserves, fees, etc.), you need to mine a new salt.
-
Deterministic Addresses: On fresh anvil with deterministic addresses, the same pool parameters will always require the same salt.
-
HookMiner Limits: HookMiner tries up to 160,444 iterations to find a valid salt. If it fails, you may need to adjust your pool parameters slightly.
-
Performance: Salt mining typically takes a few seconds to find a valid salt among ~80k attempts.
-
"HookAddressNotValid" Error: The pool address doesn't have the correct permission bits. Use HookMiner to find a valid salt.
-
"Could not find salt" Error: HookMiner couldn't find a valid salt within its iteration limit. Try adjusting pool parameters slightly (e.g., change fee by 1 wei).
-
Deployment Succeeds but Pool Not Found: Check that you're using the correct euler account and that the operator was set properly.
For production use:
- Use the EulerSwap UI which handles salt mining automatically
- Use the EulerSwap SDK which includes salt mining utilities
- Pre-mine salts for common pool configurations