Skip to main content
Looking for Contributors! This Skill needs an implementation.Contributing a Skill involves:
  1. Writing a reference implementation with full functionality
  2. Adding comprehensive tests
  3. Writing documentation with usage examples
See the ethers-provider Skill for an example of a complete Skill implementation.Interested? Open an issue or PR at github.com/evmts/voltaire.
Skill — Copyable reference implementation. Use as-is or customize. See Skills Philosophy.
Interact with Uniswap V4’s singleton architecture, custom hooks, and flash accounting system.

Why Uniswap V4?

V4 introduces major architectural changes:
  • Singleton contract — All pools in one contract (gas savings)
  • Hooks — Custom logic at every pool lifecycle point
  • Flash accounting — Net-zero balance requirements
  • Native ETH — No more WETH wrapping required
  • Dynamic fees — Hooks can modify swap fees

Planned Implementation

Pool Interaction

import { UniswapV4 } from './UniswapV4.js';

const v4 = UniswapV4({
  provider,
  poolManager: POOL_MANAGER_ADDRESS,
});

// Get pool state
const pool = await v4.getPool({
  currency0: USDC,
  currency1: WETH,
  fee: 3000,
  tickSpacing: 60,
  hooks: HOOK_ADDRESS,
});

console.log('sqrtPriceX96:', pool.sqrtPriceX96);
console.log('liquidity:', pool.liquidity);
console.log('tick:', pool.tick);

Swaps

// Execute swap through V4
const tx = await v4.swap({
  poolKey: {
    currency0: USDC,
    currency1: WETH,
    fee: 3000,
    tickSpacing: 60,
    hooks: ZERO_ADDRESS,
  },
  params: {
    zeroForOne: true,
    amountSpecified: parseUnits('1000', 6), // 1000 USDC
    sqrtPriceLimitX96: MIN_SQRT_RATIO + 1n,
  },
  signer,
});

Liquidity Provision

// Add liquidity to a V4 pool
const tx = await v4.modifyLiquidity({
  poolKey,
  params: {
    tickLower: -887220,
    tickUpper: 887220,
    liquidityDelta: parseEther('1'),
  },
  signer,
});

Hook Development

// Encode hook permissions
import { HookFlags } from './hooks.js';

const permissions = HookFlags.encode({
  beforeSwap: true,
  afterSwap: true,
  beforeAddLiquidity: false,
  afterAddLiquidity: false,
  // ...
});

// Validate hook address matches permissions
const isValid = HookFlags.validate(hookAddress, permissions);

Resources