Quickstart
Every endpoint lives under https://tacklehooks.xyz/v1. Addresses are checksummed or lowercase 0x strings, amounts are human units ("0.1"), and every response is JSON.
curl https://tacklehooks.xyz/v1/stats curl "https://tacklehooks.xyz/v1/hooks?sort=pools&limit=10" curl https://tacklehooks.xyz/v1/scan/0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
MCP for agents
The MCP server speaks streamable HTTP at https://tacklehooks.xyz/mcp, with ten tools: scan, decode_hook, inspect_hook, list_hooks, list_pools, get_pool, compute_pool_id, quote, build_swap, mine_hook_salt and get_stats.
Claude Code
claude mcp add --transport http tackle https://tacklehooks.xyz/mcp
Cursor and other clients
{
"mcpServers": {
"tackle": { "url": "https://tacklehooks.xyz/mcp" }
}
}Then ask in plain words: “which hooks on this token can take a fee?”, “quote 0.1 ETH through this pool”, “mine a beforeSwap and afterSwap address for this init code hash”.
Scanner
GET/v1/scan/:input
Each hook comes with a verdict: a tone (clear, caution, risky, missing) and four plain checks: fixed or upgradeable code, curve or custom pricing, hook fee or none, and whether LP withdrawals can be blocked.
Hooks
GET/v1/hooks?sort=pools|recent&q=&limit=25&offset=0
q searches names and addresses.GET/v1/hooks/:address
GET/v1/hooks/:address/flags
GET/v1/hooks/flags
Hook miner
The PoolManager reads a hook’s permissions from the last 14 bits of its address, so the hook has to be deployed at an address that carries exactly those bits. The miner finds the CREATE2 salt.
POST/v1/hooks/mine
flags (names) or mask, initCodeHash = keccak256(creationCode ++ constructor args), optional deployer (default: the CREATE2 deployer 0x4e59…956C).curl -X POST https://tacklehooks.xyz/v1/hooks/mine \
-H 'content-type: application/json' \
-d '{"flags":["beforeSwap","afterSwap"],"initCodeHash":"0x…"}'Deploy by sending salt ++ creationCode to the deployer. Each call starts from a random salt; if found is false, call again.
Pools
GET/v1/pools?hook=&token=&hooked=true|false&limit=25&offset=0
GET/v1/pools/:poolId
POST/v1/pools/id
Quotes
GET/v1/quote?poolId=&tokenIn=&amount=&exactOut=false&hookData=0x
curl "https://tacklehooks.xyz/v1/quote?poolId=0x…&tokenIn=0x0000000000000000000000000000000000000000&amount=0.1"
Swaps
POST/v1/swap/build
poolId, tokenIn, amount, sender, optional slippageBps (default 50), hookData, deadline.Returns the transactions to sign, in order: an ERC-20 approval to Permit2 and a Permit2 approval to the Universal Router when needed, then execute(0x10, …) with SWAP_EXACT_IN_SINGLE, SETTLE_ALL and TAKE_ALL. When no approval is pending, the swap is dry-run from the sender and the result is in simulation. Tackle never signs or sends anything.
Permission bits
Bit 13 is the highest, bit 0 the lowest. A *ReturnDelta flag needs its base flag, or the PoolManager rejects the address.
beforeInitialize1<<130x2000afterInitialize1<<120x1000beforeAddLiquidity1<<110x0800afterAddLiquidity1<<100x0400beforeRemoveLiquidity1<<90x0200afterRemoveLiquidity1<<80x0100beforeSwap1<<70x0080afterSwap1<<60x0040beforeDonate1<<50x0020afterDonate1<<40x0010beforeSwapReturnDelta1<<30x0008afterSwapReturnDelta1<<20x0004afterAddLiquidityReturnDelta1<<10x0002afterRemoveLiquidityReturnDelta1<<00x0001Contracts
Uniswap v4 on Robinhood Chain, all verified. GET /v1/chain returns the same list.
Limits and errors
120 requests a minute per IP (a mining call counts as 10). Errors come back as { "error": { "code", "message" } } with a 4xx status: bad_address, pool_not_found, quote_reverted (often a hook refusing the swap), rate_limited.
Capability notes describe what a permission makes possible, not what a hook does. They are not an audit: read the verified source before trusting a hook with real funds.