skills/uniswap_lp/SKILL.md
Provide liquidity on Uniswap V4 (Base) — deposit to pools, withdraw, collect fees.
npx skillsauth add ethereumdegen/stark-bot uniswap_lpInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Provide liquidity on Uniswap V4 pools on Base — create positions, increase/decrease liquidity, and collect fees.
say_to_user with finished_task: true until the current task is truly done.cache_as values — use exactly what is specified.weth_deposit preset.| Pool | Pool ID | Token0 | Token1 | Fee | Tick Spacing | Hooks |
|------|---------|--------|--------|-----|-------------|-------|
| STARKBOT/WETH | 0x0d64a8e0d28626511cc23fc75b81c2f03e222b14f9b944b60eecc3f4ddabeddc | WETH (0x4200000000000000000000000000000000000006) | STARKBOT (0x587Cd533F418825521f3A1daa7CCd1E7339A1B07) | 10000 (1%) | 200 | 0x0000000000000000000000000000000000000000 |
Token0/token1 order is determined by address sort (lower address first). WETH < STARKBOT by address.
| Contract | Address |
|----------|---------|
| V4 PositionManager | 0x7c5f5a4bbd8fd63184577525326123b519429bdc |
| V4 StateView | 0xa3c0c9b65bad0b08107aa264b0f3db444b867a71 |
| Permit2 | 0x000000000022D473030F116dDEE9F6B43aC78BA3 |
| WETH | 0x4200000000000000000000000000000000000006 |
| STARKBOT | 0x587Cd533F418825521f3A1daa7CCd1E7339A1B07 |
When creating a position, the user must choose a tick range. Offer these options:
Tick alignment: tickLower and tickUpper must be multiples of the pool's tick spacing (200 for STARKBOT/WETH). Round to the nearest multiple.
To compute ticks from price ratios around the current tick:
Read pool state to get current tick, price, and liquidity. No tasks needed — just direct tool calls.
{"tool": "select_web3_network", "network": "base"}
{"tool": "web3_function_call", "abi": "uniswap_v4_state_view", "contract": "0xa3c0c9b65bad0b08107aa264b0f3db444b867a71", "function": "getSlot0", "params": ["0x0d64a8e0d28626511cc23fc75b81c2f03e222b14f9b944b60eecc3f4ddabeddc"], "call_only": true}
Returns: sqrtPriceX96, tick, protocolFee, lpFee.
{"tool": "web3_function_call", "abi": "uniswap_v4_state_view", "contract": "0xa3c0c9b65bad0b08107aa264b0f3db444b867a71", "function": "getLiquidity", "params": ["0x0d64a8e0d28626511cc23fc75b81c2f03e222b14f9b944b60eecc3f4ddabeddc"], "call_only": true}
Calculate approximate price from sqrtPriceX96:
Report: current tick, sqrtPriceX96, liquidity, approximate price.
{"tool": "define_tasks", "tasks": [
"TASK 1 — Prepare: select Base, look up both tokens, check balances, read pool state (slot0 + liquidity). See LP skill 'Task 1'.",
"TASK 2 — Approve: approve both tokens for Permit2 (skip if sufficient). See LP skill 'Task 2'.",
"TASK 3 — Build tx: POST to Uniswap API /lp/create, cache response. See LP skill 'Task 3'.",
"TASK 4 — Execute: decode calldata, call LP preset, then broadcast_web3_tx. See LP skill 'Task 4'.",
"TASK 5 — Verify the LP position result and report to the user. See LP skill 'Task 5'."
]}
{"tool": "select_web3_network", "network": "base"}
{"tool": "token_lookup", "symbol": "WETH", "cache_as": "sell_token"}
{"tool": "web3_preset_function_call", "preset": "weth_balance", "network": "base", "call_only": true}
{"tool": "token_lookup", "symbol": "STARKBOT", "cache_as": "sell_token"}
{"tool": "web3_preset_function_call", "preset": "erc20_balance", "network": "base", "call_only": true}
Note: sell_token register now holds STARKBOT address (from 1d). The erc20_balance preset reads from token_address — you need to set it:
{"tool": "token_lookup", "symbol": "STARKBOT", "cache_as": "token_address"}
Then check balance:
{"tool": "web3_preset_function_call", "preset": "erc20_balance", "network": "base", "call_only": true}
{"tool": "web3_function_call", "abi": "uniswap_v4_state_view", "contract": "0xa3c0c9b65bad0b08107aa264b0f3db444b867a71", "function": "getSlot0", "params": ["0x0d64a8e0d28626511cc23fc75b81c2f03e222b14f9b944b60eecc3f4ddabeddc"], "call_only": true}
{"tool": "web3_function_call", "abi": "uniswap_v4_state_view", "contract": "0xa3c0c9b65bad0b08107aa264b0f3db444b867a71", "function": "getLiquidity", "params": ["0x0d64a8e0d28626511cc23fc75b81c2f03e222b14f9b944b60eecc3f4ddabeddc"], "call_only": true}
Report balances, current tick, price, and liquidity. Suggest tick ranges (full/wide/narrow). Ask user to confirm amounts and range. Complete with finished_task: true.
Uniswap V4 uses Permit2. Check and approve BOTH tokens if needed.
{"tool": "token_lookup", "symbol": "WETH", "cache_as": "sell_token"}
{"tool": "web3_preset_function_call", "preset": "erc20_allowance_permit2", "network": "base", "call_only": true}
If allowance is insufficient:
{"tool": "web3_preset_function_call", "preset": "erc20_approve_permit2", "network": "base"}
{"tool": "broadcast_web3_tx", "uuid": "<uuid>"}
Wait for confirmation.
{"tool": "token_lookup", "symbol": "STARKBOT", "cache_as": "sell_token"}
{"tool": "web3_preset_function_call", "preset": "erc20_allowance_permit2", "network": "base", "call_only": true}
If allowance is insufficient:
{"tool": "web3_preset_function_call", "preset": "erc20_approve_permit2", "network": "base"}
{"tool": "broadcast_web3_tx", "uuid": "<uuid>"}
Wait for confirmation.
{"tool": "task_fully_completed", "summary": "Both tokens approved for Permit2. Ready to create position."}
If both were already approved:
{"tool": "task_fully_completed", "summary": "Both tokens already approved for Permit2 — skipping."}
IMPORTANT: Use the pool state values from Task 1 (currentTick, sqrtRatioX96, poolLiquidity).
Convert amounts to raw units first:
For WETH (token0, 18 decimals):
{"tool": "to_raw_amount", "amount": "<weth_amount>", "decimals": 18, "cache_as": "lp_amount0"}
For STARKBOT (token1, 18 decimals):
{"tool": "to_raw_amount", "amount": "<starkbot_amount>", "decimals": 18, "cache_as": "lp_amount1"}
Then call the Uniswap API:
{
"tool": "web_fetch",
"url": "https://trade-api.gateway.uniswap.org/v1/lp/create",
"method": "POST",
"headers": {"x-api-key": "$UNISWAP_API_KEY"},
"body": {
"protocol": "V4",
"walletAddress": "<wallet_address>",
"chainId": 8453,
"position": {
"pool": {
"token0": "0x4200000000000000000000000000000000000006",
"token1": "0x587Cd533F418825521f3A1daa7CCd1E7339A1B07",
"fee": 10000,
"tickSpacing": 200,
"hooks": "0x0000000000000000000000000000000000000000"
},
"tickLower": "<tick_lower>",
"tickUpper": "<tick_upper>"
},
"amount0": "<raw_amount0_from_register>",
"amount1": "<raw_amount1_from_register>",
"poolLiquidity": "<from_task1>",
"currentTick": "<from_task1>",
"sqrtRatioX96": "<from_task1>",
"slippageTolerance": 50
},
"extract_mode": "raw",
"cache_as": "uni_lp_tx",
"json_path": "create"
}
The json_path: "create" extracts the transaction object from the API response's create field. The cached register will contain {to, data, value}.
After success:
{"tool": "task_fully_completed", "summary": "LP create transaction built and cached. Ready to execute."}
{"tool": "decode_calldata", "abi": "uniswap_v4_position_manager", "calldata_register": "uni_lp_tx", "cache_as": "uni_lp"}
This extracts uni_lp_contract, uni_lp_param_0, uni_lp_param_1, uni_lp_value from the cached transaction.
{"tool": "web3_preset_function_call", "preset": "uni_v4_modify_liquidities", "network": "base"}
{"tool": "broadcast_web3_tx", "uuid": "<uuid>"}
The task auto-completes when broadcast_web3_tx succeeds.
{"tool": "verify_tx_broadcast"}
Report the result:
{"tool": "task_fully_completed", "summary": "LP position created successfully."}
Used to add more liquidity to an existing position.
{"tool": "define_tasks", "tasks": [
"TASK 1 — Prepare: select Base, look up tokens, check balances, read pool state. Get tokenId from user. See LP skill 'Increase Task 1'.",
"TASK 2 — Approve: approve both tokens for Permit2 (skip if sufficient). See LP skill 'Task 2' (same as create).",
"TASK 3 — Build + Execute: POST to /lp/increase, decode, execute, then broadcast_web3_tx. See LP skill 'Increase Task 3'.",
"TASK 4 — Verify the result and report to the user. See LP skill 'Task 5' (same as create)."
]}
Same as Create Task 1, but also ask the user for their position tokenId (they can find it on the Uniswap UI or from their wallet).
Convert amounts to raw units, then call the API:
{
"tool": "web_fetch",
"url": "https://trade-api.gateway.uniswap.org/v1/lp/increase",
"method": "POST",
"headers": {"x-api-key": "$UNISWAP_API_KEY"},
"body": {
"protocol": "V4",
"tokenId": "<token_id>",
"walletAddress": "<wallet_address>",
"chainId": 8453,
"position": {
"pool": {
"token0": "0x4200000000000000000000000000000000000006",
"token1": "0x587Cd533F418825521f3A1daa7CCd1E7339A1B07",
"fee": 10000,
"tickSpacing": 200,
"hooks": "0x0000000000000000000000000000000000000000"
},
"tickLower": "<tick_lower>",
"tickUpper": "<tick_upper>"
},
"amount0": "<raw_amount0>",
"amount1": "<raw_amount1>",
"poolLiquidity": "<from_task1>",
"currentTick": "<from_task1>",
"sqrtRatioX96": "<from_task1>",
"slippageTolerance": 50
},
"extract_mode": "raw",
"cache_as": "uni_lp_tx",
"json_path": "increase"
}
Then decode and execute (same as Create Task 4):
{"tool": "decode_calldata", "abi": "uniswap_v4_position_manager", "calldata_register": "uni_lp_tx", "cache_as": "uni_lp"}
{"tool": "web3_preset_function_call", "preset": "uni_v4_modify_liquidities", "network": "base"}
{"tool": "broadcast_web3_tx", "uuid": "<uuid>"}
{"tool": "define_tasks", "tasks": [
"TASK 1 — Prepare: select Base, get tokenId and withdrawal percentage from user, read pool state. See LP skill 'Decrease Task 1'.",
"TASK 2 — Build + Execute: POST to /lp/decrease, decode, execute, then broadcast_web3_tx. See LP skill 'Decrease Task 2'.",
"TASK 3 — Verify the result and report to the user. See LP skill 'Task 5'.",
"TASK 4 — Report: report withdrawn amounts. See LP skill 'Decrease Task 4'."
]}
Select network, read pool state, ask user for:
tokenId: their position NFT token ID{
"tool": "web_fetch",
"url": "https://trade-api.gateway.uniswap.org/v1/lp/decrease",
"method": "POST",
"headers": {"x-api-key": "$UNISWAP_API_KEY"},
"body": {
"protocol": "V4",
"tokenId": "<token_id>",
"walletAddress": "<wallet_address>",
"chainId": 8453,
"position": {
"pool": {
"token0": "0x4200000000000000000000000000000000000006",
"token1": "0x587Cd533F418825521f3A1daa7CCd1E7339A1B07",
"fee": 10000,
"tickSpacing": 200,
"hooks": "0x0000000000000000000000000000000000000000"
},
"tickLower": "<tick_lower>",
"tickUpper": "<tick_upper>"
},
"liquidityPercentageToDecrease": "<percentage>",
"poolLiquidity": "<from_task1>",
"currentTick": "<from_task1>",
"sqrtRatioX96": "<from_task1>",
"slippageTolerance": 50
},
"extract_mode": "raw",
"cache_as": "uni_lp_tx",
"json_path": "decrease"
}
Then decode and execute:
{"tool": "decode_calldata", "abi": "uniswap_v4_position_manager", "calldata_register": "uni_lp_tx", "cache_as": "uni_lp"}
{"tool": "web3_preset_function_call", "preset": "uni_v4_modify_liquidities", "network": "base"}
{"tool": "broadcast_web3_tx", "uuid": "<uuid>"}
After verification, report the withdrawn token amounts and remaining position (if partial withdrawal).
{"tool": "define_tasks", "tasks": [
"TASK 1 — Prepare: select Base, get tokenId from user, read pool state. See LP skill 'Collect Task 1'.",
"TASK 2 — Build + Execute: POST to /lp/claim, decode, execute, then broadcast_web3_tx. See LP skill 'Collect Task 2'.",
"TASK 3 — Verify the result and report collected fees. See LP skill 'Task 5'."
]}
Select network, read pool state, get tokenId from user.
{
"tool": "web_fetch",
"url": "https://trade-api.gateway.uniswap.org/v1/lp/claim",
"method": "POST",
"headers": {"x-api-key": "$UNISWAP_API_KEY"},
"body": {
"protocol": "V4",
"tokenId": "<token_id>",
"walletAddress": "<wallet_address>",
"chainId": 8453,
"position": {
"pool": {
"token0": "0x4200000000000000000000000000000000000006",
"token1": "0x587Cd533F418825521f3A1daa7CCd1E7339A1B07",
"fee": 10000,
"tickSpacing": 200,
"hooks": "0x0000000000000000000000000000000000000000"
},
"tickLower": "<tick_lower>",
"tickUpper": "<tick_upper>"
},
"poolLiquidity": "<from_task1>",
"currentTick": "<from_task1>",
"sqrtRatioX96": "<from_task1>",
"slippageTolerance": 50
},
"extract_mode": "raw",
"cache_as": "uni_lp_tx",
"json_path": "claim"
}
Then decode and execute:
{"tool": "decode_calldata", "abi": "uniswap_v4_position_manager", "calldata_register": "uni_lp_tx", "cache_as": "uni_lp"}
{"tool": "web3_preset_function_call", "preset": "uni_v4_modify_liquidities", "network": "base"}
{"tool": "broadcast_web3_tx", "uuid": "<uuid>"}
| Error | Cause | Solution | |-------|-------|----------| | Insufficient token balance | Not enough WETH or STARKBOT | Check balances, reduce amounts or wrap ETH | | Insufficient gas | Not enough ETH for gas | Need ETH on Base for gas | | Allowance too low | Token not approved for Permit2 | Run approval task | | Invalid tick range | Ticks not aligned to tickSpacing | Round ticks to nearest multiple of 200 | | Pool not found | Wrong pool parameters | Verify pool config matches on-chain state | | API error | Uniswap API issue | Check API key ($UNISWAP_API_KEY), retry | | Slippage exceeded | Price moved too much | Increase slippageTolerance or retry |
weth_deposit preset.config/uniswap_pools.ron.Key concepts:
tools
Swap ERC20 tokens on Base using 0x DEX aggregator via quoter.defirelay.com
data-ai
Monitor ETH wallets for on-chain activity, detect whale trades, and track transaction history on Ethereum Mainnet and Base
tools
Manage Supabase projects - databases, migrations, edge functions, storage, and secrets using the Supabase CLI.
testing
Autonomous DeFi spot trader — scans DexScreener and Bankr signals, makes trade decisions, executes swaps on Base