Install
$ agentstack add skill-uniswap-uniswap-ai-v4-sdk-integration ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Uniswap v4 SDK Integration
> App-layer SDK for swaps, quotes, and liquidity. For Solidity hook contracts, use the > uniswap-hooks skill. For Trading API or v3-centric swaps, use the swap-integration skill.
When to Use
- Token swap UI (single-hop or multi-hop)
- Quote/price display before executing a trade
- Liquidity position management (add/remove/collect)
- Pool state reads (price, tick, liquidity)
Packages
npm i @uniswap/v4-sdk @uniswap/sdk-core @uniswap/universal-router-sdk
v4 vs v3 Decision Table
| Aspect | v3 | v4 | | ------------------ | -------------------------- | --------------------------------------------- | | Swap execution | SwapRouter directly | Universal Router required (V4Planner) | | Pool architecture | One contract per pool | Singleton PoolManager | | Pool state reads | Direct pool contract | StateView contract | | Native ETH | Wrap to WETH | Native support (Ether.onChain(chainId)) | | Position NFTs | NonfungiblePositionManager | PositionManager + multicall | | Fee collection | Explicit collect() | Automatic on position modification | | Position discovery | Onchain enumeration | Offchain event indexing | | Token approvals | Direct approve | Permit2 required | | Contract addresses | Same across chains | Different per chain — verify from deployments |
Core Contracts (Per Chain)
Look up addresses at — they differ per chain.
| Contract | Purpose | | ---------------- | --------------------------------------------------------------------------------------- | | PoolManager | Singleton pool state | | Universal Router | Swap execution entry point | | Quoter | Offchain quote simulation (callStatic) | | StateView | Pool state reads (getSlot0, getLiquidity) | | PositionManager | LP position lifecycle | | Permit2 | Token approval layer (same across chains: 0x000000000022D473030F116dDEE9F6B43aC78BA3) |
Swap Pattern (Universal Router)
All swaps use: V4Planner -> RoutePlanner -> Universal Router execute().
Single-hop (exact input):
import { Actions, V4Planner } from '@uniswap/v4-sdk';
import { CommandType, RoutePlanner } from '@uniswap/universal-router-sdk';
const v4Planner = new V4Planner();
v4Planner.addAction(Actions.SWAP_EXACT_IN_SINGLE, [swapConfig]);
v4Planner.addAction(Actions.SETTLE_ALL, [inputCurrency, amountIn]);
v4Planner.addAction(Actions.TAKE_ALL, [outputCurrency, amountOutMinimum]);
const routePlanner = new RoutePlanner();
routePlanner.addCommand(CommandType.V4_SWAP, [v4Planner.actions, v4Planner.params]);
const deadline = Math.floor(Date.now() / 1000) + 3600;
// Note: universalRouter.execute() is pseudocode for the viem call pattern.
// With viem, use: walletClient.writeContract({ address: UNIVERSAL_ROUTER_ADDRESS, abi: universalRouterAbi, functionName: 'execute', args: [routePlanner.commands, [v4Planner.finalize()], deadline], ...txOptions })
await universalRouter.execute(routePlanner.commands, [v4Planner.finalize()], deadline, txOptions);
Multi-hop (exact input):
import { Actions, V4Planner, encodeMultihopExactInPath } from '@uniswap/v4-sdk';
import { CommandType, RoutePlanner } from '@uniswap/universal-router-sdk';
const v4Planner = new V4Planner();
// Build multi-hop path: tokenA -> tokenB -> tokenC
const path = encodeMultihopExactInPath([poolKeyAB, poolKeyBC], tokenA);
v4Planner.addAction(Actions.SWAP_EXACT_IN, [{ path, amountIn, amountOutMinimum }]);
// SETTLE_ALL uses first pool's input currency; TAKE_ALL uses last pool's output currency
v4Planner.addAction(Actions.SETTLE_ALL, [tokenA, amountIn]);
v4Planner.addAction(Actions.TAKE_ALL, [tokenC, amountOutMinimum]);
const routePlanner = new RoutePlanner();
routePlanner.addCommand(CommandType.V4_SWAP, [v4Planner.actions, v4Planner.params]);
const deadline = Math.floor(Date.now() / 1000) + 3600;
// Note: universalRouter.execute() is pseudocode for the viem call pattern.
// With viem, use: walletClient.writeContract({ address: UNIVERSAL_ROUTER_ADDRESS, abi: universalRouterAbi, functionName: 'execute', args: [routePlanner.commands, [v4Planner.finalize()], deadline], ...txOptions })
await universalRouter.execute(routePlanner.commands, [v4Planner.finalize()], deadline, txOptions);
SwapConfig (SwapExactInSingle):
const swapConfig = {
poolKey: { currency0, currency1, fee, tickSpacing, hooks },
zeroForOne,
amountIn,
amountOutMinimum,
hookData: '0x00',
};
Quoting Pattern
Use the Quoter contract with callStatic — this simulates the swap offchain without executing it or spending gas.
const quote = await quoterContract.callStatic.quoteExactInputSingle({
poolKey,
zeroForOne,
exactAmount: amountIn,
hookData: '0x00',
});
Four available methods:
quoteExactInputSingle— single-hop, exact input amountquoteExactInput— multi-hop, exact input amountquoteExactOutputSingle— single-hop, exact output amountquoteExactOutput— multi-hop, exact output amount
Pool State Reads (StateView)
import { Pool } from '@uniswap/v4-sdk';
const poolId = Pool.getPoolId(currency0, currency1, fee, tickSpacing, hooks);
const [slot0, liquidity] = await Promise.all([
stateViewContract.getSlot0(poolId),
stateViewContract.getLiquidity(poolId),
]);
// slot0 → { sqrtPriceX96, tick, protocolFee, lpFee }
ERC20 Approval Flow (Permit2)
ERC20 swaps require two approvals — token -> Permit2, then Permit2 -> Universal Router:
// Step 1: Approve Permit2 on the token contract
await erc20Contract.approve(PERMIT2_ADDRESS, MaxUint256);
// Step 2: Approve Universal Router on Permit2
await permit2Contract.approve(tokenAddress, UNIVERSAL_ROUTER_ADDRESS, MAX_UINT160, deadline);
Native ETH swaps bypass both approvals — pass value in the transaction options instead.
Position Management (PositionManager)
All operations use PositionManager.multicall():
| Operation | SDK Method | | ---------------- | ----------------------------------------------------------- | | Add liquidity | V4PositionManager.addCallParameters(position, options) | | Remove liquidity | V4PositionManager.removeCallParameters(position, options) | | Collect fees | V4PositionManager.collectCallParameters(options) | | Create position | V4PositionManager.createCallParameters(position, options) |
const { calldata, value } = V4PositionManager.addCallParameters(position, {
slippageTolerance: new Percent(50, 10_000),
deadline: deadline.toString(),
tokenId: tokenId.toString(),
useNative: token0.isNative ? Ether.onChain(chainId) : undefined,
batchPermit,
hookData: '0x',
});
await walletClient.writeContract({
address: POSITION_MANAGER_ADDRESS,
functionName: 'multicall',
args: [[calldata]],
value: BigInt(value),
});
Strict Rules
- NEVER call PoolManager directly for swaps — ALWAYS route through Universal Router.
- NEVER assume contract addresses are the same across chains — look up from the deployments page.
- NEVER call Quoter onchain (gas expensive) — ALWAYS use
callStaticfor offchain simulation. - NEVER skip Permit2 for ERC20 swaps — direct
approveto Universal Router will not work. - ALWAYS set a deadline on swaps and LP operations.
- ALWAYS handle native ETH with
Ether.onChain(chainId), not WETH, in v4 pool contexts. - ALWAYS use
Pool.getPoolId()to compute pool identifiers — do not construct manually.
Links
- SDK overview:
- Swap guides:
- Liquidity guide:
- Pool data:
- Deployments:
- npm:
Related Skills
swap-integration— Trading API and v3-centric swap integration (not direct v4 SDK)uniswap-hooks— Solidity hook contract generation (not app-layer SDK)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Uniswap
- Source: Uniswap/uniswap-ai
- License: MIT
- Homepage: https://developers.uniswap.org
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.