{
  "axon_version": "1.0.0",
  "protocol": {
    "name": "Uniswap V3",
    "slug": "uniswap-v3",
    "version": "v3",
    "description": "Decentralized exchange with concentrated liquidity AMM. The most widely used DEX on Ethereum and L2s. Supports single-hop and multi-hop swaps with configurable fee tiers.",
    "category": "dex",
    "chain": {
      "id": 1,
      "name": "ethereum",
      "network": "mainnet"
    },
    "contracts": {
      "swap_router": {
        "address": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
        "label": "SwapRouter (V1 — legacy)",
        "verified": true
      },
      "swap_router_02": {
        "address": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
        "label": "SwapRouter02 (V3SwapRouter — recommended)",
        "verified": true
      },
      "universal_router": {
        "address": "0x66a9893cC07D91D95644AEDD05D03f95e1dBA8Af",
        "label": "UniversalRouter",
        "verified": true
      },
      "factory": {
        "address": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
        "label": "UniswapV3Factory",
        "verified": true
      },
      "quoter_v2": {
        "address": "0x61fFE014bA17989E743c5F6cB21bF9697530B21e",
        "label": "QuoterV2",
        "verified": true
      },
      "permit2": {
        "address": "0x000000000022D473030F116dDEE9F6B43aC78BA3",
        "label": "Permit2 (Canonical)",
        "verified": true
      },
      "nft_position_manager": {
        "address": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
        "label": "NonfungiblePositionManager",
        "verified": true
      }
    },
    "links": {
      "website": "https://uniswap.org",
      "docs": "https://docs.uniswap.org",
      "github": "https://github.com/Uniswap/v3-core",
      "governance": "https://gov.uniswap.org"
    }
  },
  "actions": [
    {
      "id": "exact_input_single",
      "name": "Exact Input Single Swap",
      "description": "Swap an exact amount of one token for the maximum possible amount of another token through a single liquidity pool. Use QuoterV2 to estimate output before executing.",
      "type": "swap",
      "parameters": [
        {
          "name": "tokenIn",
          "type": "address",
          "required": true,
          "description": "Contract address of the input token (ERC-20). Use WETH address for native ETH swaps."
        },
        {
          "name": "tokenOut",
          "type": "address",
          "required": true,
          "description": "Contract address of the desired output token (ERC-20)"
        },
        {
          "name": "fee",
          "type": "uint24",
          "required": true,
          "description": "Pool fee tier in hundredths of a basis point",
          "constraints": {
            "enum": [100, 500, 3000, 10000]
          }
        },
        {
          "name": "recipient",
          "type": "address",
          "required": true,
          "description": "Address that will receive the output tokens"
        },
        {
          "name": "amountIn",
          "type": "uint256",
          "required": true,
          "description": "Exact amount of input tokens to swap (in the token's smallest unit)",
          "constraints": {
            "min": "1"
          }
        },
        {
          "name": "amountOutMinimum",
          "type": "uint256",
          "required": true,
          "description": "Minimum acceptable output amount (slippage protection). Calculate as: quotedAmount * (1 - slippageBps / 10000).",
          "constraints": {
            "min": "0"
          }
        },
        {
          "name": "sqrtPriceLimitX96",
          "type": "uint256",
          "required": false,
          "description": "Price limit for partial fills. Set to 0 for no limit.",
          "default": "0"
        },
        {
          "name": "deadline",
          "type": "uint256",
          "required": true,
          "description": "Unix timestamp after which the transaction will revert. Passed via multicall(uint256 deadline, bytes[] data) on SwapRouter02.",
          "constraints": {
            "min": "1"
          }
        }
      ],
      "constraints": {
        "min_amount": "1",
        "max_slippage_bps": 5000,
        "deadline_required": true,
        "supported_tokens": "any_erc20"
      },
      "approvals": [
        {
          "type": "erc20_approve",
          "token": "tokenIn",
          "spender": "swap_router_02",
          "amount": "exact_or_max"
        },
        {
          "type": "permit2",
          "token": "tokenIn",
          "spender": "universal_router",
          "amount": "exact"
        }
      ],
      "transaction_flow": [
        {
          "step": 1,
          "action": "quote",
          "description": "Call QuoterV2 off-chain (via eth_call) to get expected output amount, price impact, and gas estimate",
          "contract": "quoter_v2",
          "method": "quoteExactInputSingle((address,address,uint256,uint24,uint160))",
          "conditional": "always",
          "returns": ["amountOut", "sqrtPriceX96After", "initializedTicksCrossed", "gasEstimate"]
        },
        {
          "step": 2,
          "action": "check_allowance",
          "description": "Check if SwapRouter02 has sufficient allowance to spend tokenIn",
          "contract": "tokenIn",
          "method": "allowance(address,address)",
          "conditional": "always",
          "returns": ["allowance"]
        },
        {
          "step": 3,
          "action": "approve",
          "description": "Approve SwapRouter02 to spend input tokens. Alternative: approve Permit2 once, then use signature-based permits.",
          "contract": "tokenIn",
          "method": "approve(address,uint256)",
          "conditional": "if_allowance_insufficient"
        },
        {
          "step": 4,
          "action": "execute",
          "description": "Execute the exact input single swap via SwapRouter02 wrapped in multicall for deadline",
          "contract": "swap_router_02",
          "method": "exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))",
          "returns": ["amountOut"]
        }
      ]
    },
    {
      "id": "exact_output_single",
      "name": "Exact Output Single Swap",
      "description": "Swap the minimum necessary amount of an input token to receive an exact amount of the output token through a single pool.",
      "type": "swap",
      "parameters": [
        {
          "name": "tokenIn",
          "type": "address",
          "required": true,
          "description": "Contract address of the input token"
        },
        {
          "name": "tokenOut",
          "type": "address",
          "required": true,
          "description": "Contract address of the desired output token"
        },
        {
          "name": "fee",
          "type": "uint24",
          "required": true,
          "description": "Pool fee tier in hundredths of a basis point",
          "constraints": {
            "enum": [100, 500, 3000, 10000]
          }
        },
        {
          "name": "recipient",
          "type": "address",
          "required": true,
          "description": "Address that receives the output tokens"
        },
        {
          "name": "amountOut",
          "type": "uint256",
          "required": true,
          "description": "Exact amount of output tokens desired (in the token's smallest unit)",
          "constraints": {
            "min": "1"
          }
        },
        {
          "name": "amountInMaximum",
          "type": "uint256",
          "required": true,
          "description": "Maximum amount of input tokens willing to spend (slippage protection)",
          "constraints": {
            "min": "1"
          }
        },
        {
          "name": "sqrtPriceLimitX96",
          "type": "uint256",
          "required": false,
          "description": "Price limit for the swap. Set to 0 for no limit.",
          "default": "0"
        },
        {
          "name": "deadline",
          "type": "uint256",
          "required": true,
          "description": "Unix timestamp after which the transaction will revert.",
          "constraints": {
            "min": "1"
          }
        }
      ],
      "constraints": {
        "min_amount": "1",
        "max_slippage_bps": 5000,
        "deadline_required": true,
        "supported_tokens": "any_erc20"
      },
      "approvals": [
        {
          "type": "erc20_approve",
          "token": "tokenIn",
          "spender": "swap_router_02",
          "amount": "exact_or_max"
        },
        {
          "type": "permit2",
          "token": "tokenIn",
          "spender": "universal_router",
          "amount": "exact"
        }
      ],
      "transaction_flow": [
        {
          "step": 1,
          "action": "quote",
          "description": "Call QuoterV2 off-chain to estimate required input amount for desired output",
          "contract": "quoter_v2",
          "method": "quoteExactOutputSingle((address,address,uint256,uint24,uint160))",
          "conditional": "always",
          "returns": ["amountIn", "sqrtPriceX96After", "initializedTicksCrossed", "gasEstimate"]
        },
        {
          "step": 2,
          "action": "check_allowance",
          "description": "Check if SwapRouter02 has sufficient allowance (must cover amountInMaximum)",
          "contract": "tokenIn",
          "method": "allowance(address,address)",
          "conditional": "always",
          "returns": ["allowance"]
        },
        {
          "step": 3,
          "action": "approve",
          "description": "Approve SwapRouter02 to spend amountInMaximum of input tokens",
          "contract": "tokenIn",
          "method": "approve(address,uint256)",
          "conditional": "if_allowance_insufficient"
        },
        {
          "step": 4,
          "action": "execute",
          "description": "Execute the exact output single swap",
          "contract": "swap_router_02",
          "method": "exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))",
          "returns": ["amountIn"]
        },
        {
          "step": 5,
          "action": "refund",
          "description": "Refund excess ETH if using native token as input",
          "contract": "swap_router_02",
          "method": "refundETH()",
          "conditional": "if_native_token_overpaid"
        }
      ]
    },
    {
      "id": "exact_input_multi",
      "name": "Exact Input Multi-Hop Swap",
      "description": "Swap an exact amount of an input token through multiple pools to maximize output. Path encoded as (token, fee, token, fee, token) in forward order.",
      "type": "swap",
      "parameters": [
        {
          "name": "path",
          "type": "bytes",
          "required": true,
          "description": "ABI-encoded swap path: tokenIn (20 bytes) + fee (3 bytes) + intermediateToken (20 bytes) + fee (3 bytes) + tokenOut (20 bytes). Forward order."
        },
        {
          "name": "recipient",
          "type": "address",
          "required": true,
          "description": "Address that will receive the final output tokens"
        },
        {
          "name": "amountIn",
          "type": "uint256",
          "required": true,
          "description": "Exact amount of the first token in the path to swap",
          "constraints": {
            "min": "1"
          }
        },
        {
          "name": "amountOutMinimum",
          "type": "uint256",
          "required": true,
          "description": "Minimum acceptable output of the final token (slippage protection)",
          "constraints": {
            "min": "0"
          }
        },
        {
          "name": "deadline",
          "type": "uint256",
          "required": true,
          "description": "Unix timestamp after which the transaction will revert.",
          "constraints": {
            "min": "1"
          }
        }
      ],
      "constraints": {
        "min_amount": "1",
        "max_slippage_bps": 5000,
        "deadline_required": true,
        "supported_tokens": "any_erc20"
      },
      "approvals": [
        {
          "type": "erc20_approve",
          "token": "tokenIn",
          "spender": "swap_router_02",
          "amount": "exact_or_max"
        },
        {
          "type": "permit2",
          "token": "tokenIn",
          "spender": "universal_router",
          "amount": "exact"
        }
      ],
      "transaction_flow": [
        {
          "step": 1,
          "action": "quote",
          "description": "Call QuoterV2.quoteExactInput off-chain to estimate final output across all hops",
          "contract": "quoter_v2",
          "method": "quoteExactInput(bytes,uint256)",
          "conditional": "always",
          "returns": ["amountOut", "sqrtPriceX96AfterList", "initializedTicksCrossedList", "gasEstimate"]
        },
        {
          "step": 2,
          "action": "check_allowance",
          "description": "Check if SwapRouter02 has sufficient allowance for the first token in the path",
          "contract": "tokenIn",
          "method": "allowance(address,address)",
          "conditional": "always",
          "returns": ["allowance"]
        },
        {
          "step": 3,
          "action": "approve",
          "description": "Approve SwapRouter02 to spend the first token in the path",
          "contract": "tokenIn",
          "method": "approve(address,uint256)",
          "conditional": "if_allowance_insufficient"
        },
        {
          "step": 4,
          "action": "execute",
          "description": "Execute the multi-hop exact input swap atomically through all pools in the path",
          "contract": "swap_router_02",
          "method": "exactInput((bytes,address,uint256,uint256))",
          "returns": ["amountOut"]
        }
      ]
    },
    {
      "id": "exact_output_multi",
      "name": "Exact Output Multi-Hop Swap",
      "description": "Swap through multiple pools to receive an exact amount of the output token. Path encoded in REVERSE order (tokenOut → tokenIn).",
      "type": "swap",
      "parameters": [
        {
          "name": "path",
          "type": "bytes",
          "required": true,
          "description": "ABI-encoded swap path in REVERSE order: tokenOut (20 bytes) + fee (3 bytes) + intermediateToken (20 bytes) + fee (3 bytes) + tokenIn (20 bytes)."
        },
        {
          "name": "recipient",
          "type": "address",
          "required": true,
          "description": "Address that will receive the exact output tokens"
        },
        {
          "name": "amountOut",
          "type": "uint256",
          "required": true,
          "description": "Exact amount of the final output token desired",
          "constraints": {
            "min": "1"
          }
        },
        {
          "name": "amountInMaximum",
          "type": "uint256",
          "required": true,
          "description": "Maximum input tokens willing to spend (slippage protection)",
          "constraints": {
            "min": "1"
          }
        },
        {
          "name": "deadline",
          "type": "uint256",
          "required": true,
          "description": "Unix timestamp after which the transaction will revert.",
          "constraints": {
            "min": "1"
          }
        }
      ],
      "constraints": {
        "min_amount": "1",
        "max_slippage_bps": 5000,
        "deadline_required": true,
        "supported_tokens": "any_erc20"
      },
      "approvals": [
        {
          "type": "erc20_approve",
          "token": "tokenIn",
          "spender": "swap_router_02",
          "amount": "exact_or_max"
        },
        {
          "type": "permit2",
          "token": "tokenIn",
          "spender": "universal_router",
          "amount": "exact"
        }
      ],
      "transaction_flow": [
        {
          "step": 1,
          "action": "quote",
          "description": "Call QuoterV2.quoteExactOutput off-chain to estimate required input across all hops. Path must be in reverse order.",
          "contract": "quoter_v2",
          "method": "quoteExactOutput(bytes,uint256)",
          "conditional": "always",
          "returns": ["amountIn", "sqrtPriceX96AfterList", "initializedTicksCrossedList", "gasEstimate"]
        },
        {
          "step": 2,
          "action": "check_allowance",
          "description": "Check allowance for input token (last token in the reversed path)",
          "contract": "tokenIn",
          "method": "allowance(address,address)",
          "conditional": "always",
          "returns": ["allowance"]
        },
        {
          "step": 3,
          "action": "approve",
          "description": "Approve SwapRouter02 to spend amountInMaximum of the input token",
          "contract": "tokenIn",
          "method": "approve(address,uint256)",
          "conditional": "if_allowance_insufficient"
        },
        {
          "step": 4,
          "action": "execute",
          "description": "Execute the multi-hop exact output swap",
          "contract": "swap_router_02",
          "method": "exactOutput((bytes,address,uint256,uint256))",
          "returns": ["amountIn"]
        },
        {
          "step": 5,
          "action": "refund",
          "description": "Refund excess ETH if using native token as input",
          "contract": "swap_router_02",
          "method": "refundETH()",
          "conditional": "if_native_token_overpaid"
        }
      ]
    }
  ],
  "risk": {
    "audit_status": {
      "audited": true,
      "auditors": ["Trail of Bits", "ABDK Consulting", "Consensys Diligence"],
      "last_audit_date": "2021-03-23",
      "audit_reports": [
        "https://github.com/Uniswap/v3-core/tree/main/audits"
      ]
    },
    "tvl": {
      "current_usd": 4800000000,
      "source": "defillama",
      "last_updated": "2026-03-07T00:00:00Z"
    },
    "incidents": [
      {
        "date": "2023-07-11",
        "severity": "info",
        "title": "Frontend DNS attack",
        "description": "Uniswap frontend briefly compromised via DNS hijacking. Smart contracts were unaffected.",
        "resolved": true,
        "post_mortem": "https://blog.uniswap.org"
      }
    ],
    "risk_score": {
      "overall": "A+",
      "smart_contract": "A+",
      "centralization": "A",
      "oracle_dependence": "A+",
      "liquidity": "A+"
    }
  },
  "fees": {
    "model": "per_trade",
    "tiers": [
      {
        "name": "ultra_low",
        "fee_bps": 1,
        "description": "0.01% — Stablecoin pairs (e.g., USDC/USDT, DAI/USDC)",
        "conditions": "fee parameter = 100, tick spacing = 1"
      },
      {
        "name": "low",
        "fee_bps": 5,
        "description": "0.05% — Highly correlated pairs (e.g., ETH/stETH)",
        "conditions": "fee parameter = 500, tick spacing = 10"
      },
      {
        "name": "medium",
        "fee_bps": 30,
        "description": "0.30% — Most pairs (e.g., WETH/USDC)",
        "conditions": "fee parameter = 3000, tick spacing = 60"
      },
      {
        "name": "high",
        "fee_bps": 100,
        "description": "1.00% — Exotic pairs",
        "conditions": "fee parameter = 10000, tick spacing = 200"
      }
    ],
    "gas_estimates": {
      "exact_input_single": "150000",
      "exact_output_single": "165000",
      "exact_input_multi": "270000",
      "exact_output_multi": "300000",
      "approve": "46000",
      "permit2_approve": "65000"
    }
  }
}