@steerprotocol/uniswap-position-quoter
v2.0.1
Published
Uniswap Position Quoter for management of single/multiple position re-balancing
Readme
🎯 Uniswap Position Quoter
High-precision rebalance calculations for multi-position liquidity strategies
✨ Features
- 🎯 99% Accuracy - Precise rebalance calculations for concentrated liquidity
- 🏭 Factory Pattern - Simple, automatic protocol detection
- 🔌 Multi-Protocol - Supports 9+ DEX protocols out of the box
- 📦 TypeScript Native - Full type safety and IntelliSense support
- 🎨 Modular Architecture - Clean, maintainable codebase
- ⚡ Zero Config - Works with sensible defaults
- 🔧 Extensible - Easy to add new protocols
🆕 What's New in v2.0.0
SwapCalculator - High-Level Orchestrator
The new SwapCalculator class provides a simplified, all-in-one API for swap calculations:
import { SwapCalculator } from '@steerprotocol/uniswap-position-quoter';
const calculator = new SwapCalculator(signer, 'arbitrum');
const result = await calculator.calculateSwapForVault({
vaultAddress: '0x...',
beaconName: 'UniswapV3',
token0: '0x...',
token1: '0x...',
newPositions: positions,
bal0: 1000000000000000000n,
bal1: 2000000000000000000n,
poolAddress: '0x...',
poolFee: 3000,
sqrtPriceX96: 79228162514264337593543950336n,
slippage: 0.01,
});Dynamic Quoter Address Resolution
No more manual quoter address management! The SDK now includes network configurations for automatic address resolution:
// Automatically resolves quoter addresses from network config
const calculator = new SwapCalculator(signer, 'arbitrum');Helper Modules
Seven new helper modules for advanced use cases:
AbiManager- Protocol-specific ABI resolutionContractFactory- Ethers.js contract instantiationProtocolDetector- Automatic protocol detectionPositionExtractor- Position data extractionBalanceQuerier- Vault balance queriesPoolStateQuerier- Pool state queriesNetworkConfig- Network-specific configurations
Breaking Changes
See the Migration Guide below for details on upgrading from v1.x.
📖 Table of Contents
- Installation
- Quick Start
- Supported Protocols
- API Reference
- Advanced Usage
- Examples
- Documentation
- Contributing
📦 Installation
# npm
npm install @steerprotocol/uniswap-position-quoter
# yarn
yarn add @steerprotocol/uniswap-position-quoter
# pnpm
pnpm add @steerprotocol/uniswap-position-quoter🚀 Quick Start
Basic Usage
The simplest way to use the SDK - just 3 steps:
import {
CustomRouterFactory,
NoopLogger,
} from '@steerprotocol/uniswap-position-quoter';
import { ethers } from 'ethers';
// 1. Create the factory
const factory = new CustomRouterFactory(NoopLogger);
// 2. Create a router (automatic protocol detection)
const router = factory.createCustomRouter({
beaconName: 'UniswapV3', // Your vault's beacon name
quoterV2: quoterContract, // Your QuoterV2 contract
poolObj: poolContract, // Your pool contract
});
// 3. Get swap amount for rebalancing
const result = await router.getSwapAmount(
poolContract,
positions, // Your desired positions
token0Balance, // Current token0 balance
token1Balance, // Current token1 balance
token0Address,
token1Address,
poolFee,
10, // Max iterations
);
console.log('Swap amount:', result.amount.toString());
console.log(
'Direction:',
result.zeroForOne ? 'Token0 → Token1' : 'Token1 → Token0',
);Complete Example
import {
CustomRouterFactory,
NoopLogger,
type Position,
type SwapResult,
} from '@steerprotocol/uniswap-position-quoter';
import { ethers } from 'ethers';
// Setup
const provider = new ethers.JsonRpcProvider(RPC_URL);
const quoterContract = new ethers.Contract(QUOTER_ADDRESS, QuoterABI, provider);
const poolContract = new ethers.Contract(POOL_ADDRESS, PoolABI, provider);
// Create factory
const factory = new CustomRouterFactory(NoopLogger);
// Create router
const router = factory.createCustomRouter({
beaconName: 'UniswapV3',
quoterV2: quoterContract,
poolObj: poolContract,
});
// Define your liquidity positions
const positions: Position[] = [
{
lowerTick: -887220,
upperTick: 887220,
weight: 1,
},
];
// Get optimal swap amount
const result: SwapResult = await router.getSwapAmount(
poolContract,
positions,
ethers.parseEther('100'), // 100 token0
ethers.parseEther('100'), // 100 token1
TOKEN0_ADDRESS,
TOKEN1_ADDRESS,
3000, // 0.3% fee
10, // max iterations
);
// Use the result
if (result.zeroForOne) {
console.log(`Swap ${result.amount} of token0 for token1`);
} else {
console.log(`Swap ${result.amount} of token1 for token0`);
}🎨 Supported Protocols
The SDK automatically detects and supports the following protocols:
| Protocol | Description | Special Config | | ----------------------- | ------------------------- | ------------------------- | | Uniswap V3 | Standard Uniswap V3 pools | None | | Uniswap V4 | Latest Uniswap version | None | | Algebra | Algebra DEX | None | | Algebra Integral | Algebra Integral variants | None | | Algebra Integral V2 | With optional deployer | Optional deployer address | | ThickV2 | ThickV2 protocol | None | | Aerodrome | Aerodrome DEX | None | | Shadow | Shadow protocol | None | | PoolShark | PoolShark DEX | None |
📚 API Reference
CustomRouterFactory
The main entry point for the SDK.
import {
CustomRouterFactory,
NoopLogger,
} from '@steerprotocol/uniswap-position-quoter';
const factory = new CustomRouterFactory(logger);createCustomRouter(params)
Creates a router for the specified protocol.
Parameters:
beaconName: string- Your vault's beacon namequoterV2: Contract- QuoterV2 contract instancepoolObj: Contract- Pool contract instanceprotocolParams?: object- Optional protocol-specific parameters
Returns: CustomRouter - A router instance for your protocol
Example:
const router = factory.createCustomRouter({
beaconName: 'UniswapV3',
quoterV2: quoterContract,
poolObj: poolContract,
});Router Methods
getSwapAmount()
Calculates the optimal swap amount for rebalancing positions.
Parameters:
pool: Contract- Pool contractpositions: Position[]- Desired liquidity positionstoken0Balance: BigNumber- Current token0 balancetoken1Balance: BigNumber- Current token1 balancetoken0Address: string- Token0 addresstoken1Address: string- Token1 addressfee: number- Pool fee (e.g., 3000 for 0.3%)maxIterations: number- Maximum calculation iterations
Returns: Promise<SwapResult>
{
amount: BigNumber, // Amount to swap
zeroForOne: boolean // true: swap token0→token1, false: token1→token0
}🔧 Advanced Usage
Protocol-Specific Parameters
Some protocols require additional configuration:
import {
CustomRouterFactory,
NoopLogger,
} from '@steerprotocol/uniswap-position-quoter';
const factory = new CustomRouterFactory(NoopLogger);
// Algebra Integral V2 with custom deployer (e.g., Blackhole)
const router = factory.createCustomRouter({
beaconName: 'AlgebraIntegral_v2_0_Blackhole',
quoterV2: quoterContract,
poolObj: poolContract,
protocolParams: {
algebraIntegralV2Deployer: '0x1234567890123456789012345678901234567890',
},
});Custom Logger
Implement your own logger for production monitoring:
import {
CustomRouterFactory,
type Logger,
} from '@steerprotocol/uniswap-position-quoter';
const myLogger: Logger = {
log: (payload, msg, ...args) => console.log(msg, payload),
info: (payload, msg, ...args) => console.info(msg, payload),
error: (payload, msg, ...args) => console.error(msg, payload),
warn: (payload, msg, ...args) => console.warn(msg, payload),
debug: (payload, msg, ...args) => console.debug(msg, payload),
};
const factory = new CustomRouterFactory(myLogger);TypeScript Types
Full TypeScript support with exported types:
import type {
Position,
SwapResult,
GetSwapAmountOptions,
CreateCustomRouterParams,
ProtocolSpecificParams,
} from '@steerprotocol/uniswap-position-quoter';
const positions: Position[] = [
{ lowerTick: -1000, upperTick: 1000, weight: 1 },
];
const result: SwapResult = await router.getSwapAmount(/* ... */);💡 Examples
Example 1: Simple Uniswap V3 Rebalance
import {
CustomRouterFactory,
NoopLogger,
} from '@steerprotocol/uniswap-position-quoter';
const factory = new CustomRouterFactory(NoopLogger);
const router = factory.createCustomRouter({
beaconName: 'UniswapV3',
quoterV2: quoterContract,
poolObj: poolContract,
});
const result = await router.getSwapAmount(
poolContract,
[{ lowerTick: -887220, upperTick: 887220, weight: 1 }],
currentToken0Balance,
currentToken1Balance,
token0Address,
token1Address,
3000,
10,
);Example 2: Multi-Position Strategy
const positions = [
{ lowerTick: -887220, upperTick: -443610, weight: 2 }, // Wide position
{ lowerTick: -443610, upperTick: 443610, weight: 5 }, // Main position
{ lowerTick: 443610, upperTick: 887220, weight: 2 }, // Wide position
];
const result = await router.getSwapAmount(
poolContract,
positions,
token0Balance,
token1Balance,
token0Address,
token1Address,
3000,
15, // More iterations for complex strategies
);Example 3: Protocol with Special Configuration
// For protocols like Blackhole that need deployer address
const router = factory.createCustomRouter({
beaconName: 'AlgebraIntegral_v2_0_Blackhole',
quoterV2: quoterContract,
poolObj: poolContract,
protocolParams: {
algebraIntegralV2Deployer: process.env.BLACKHOLE_DEPLOYER,
},
});🔄 Migration Guide (from v1.x to v2.0.0)
Overview
v2.0.0 introduces significant enhancements while maintaining backward compatibility for existing code. The main addition is the SwapCalculator high-level API.
What's Changed
✅ Backward Compatible (No Changes Required)
The existing factory pattern continues to work exactly as before:
// v1.x code - Still works in v2.0.0
import {
CustomRouterFactory,
NoopLogger,
} from '@steerprotocol/uniswap-position-quoter';
const factory = new CustomRouterFactory(NoopLogger);
const router = factory.createCustomRouter({
beaconName: 'UniswapV3',
quoterV2: quoterContract,
poolObj: poolContract,
});
const result = await router.getSwapAmount(/* ... */);🆕 New in v2.0.0
1. SwapCalculator (Recommended for New Code)
The new high-level API simplifies complex workflows:
// v2.0.0 - New simplified API
import { SwapCalculator } from '@steerprotocol/uniswap-position-quoter';
const calculator = new SwapCalculator(signer, 'arbitrum');
const result = await calculator.calculateSwapForVault({
vaultAddress: '0x...',
beaconName: 'UniswapV3',
token0: '0x...',
token1: '0x...',
newPositions: positions,
bal0: balance0,
bal1: balance1,
poolAddress: '0x...',
poolFee: 3000,
sqrtPriceX96: currentSqrtPrice,
slippage: 0.01,
});2. Helper Modules
Seven new helper modules are now available for advanced use cases:
import {
AbiManager,
ContractFactory,
QuoterFactory,
PositionExtractor,
BalanceQuerier,
PoolStateQuerier,
getNetworkConfig,
} from '@steerprotocol/uniswap-position-quoter';3. Dynamic Quoter Resolution
No more manual quoter address management:
// Before (v1.x) - Manual address required
const router = factory.createCustomRouter({
beaconName: 'UniswapV3',
quoterV2: new Contract(QUOTER_ADDRESS, abi, signer), // Had to know the address
poolObj: poolContract,
});
// After (v2.0) - Automatic resolution with SwapCalculator
const calculator = new SwapCalculator(signer, 'arbitrum');
// Quoter address resolved automatically from network configMigration Steps
- No action required for existing code - it will continue to work
- For new features, consider using
SwapCalculatorfor simpler implementations - For advanced use cases, leverage the new helper modules
Breaking Changes
None. v2.0.0 is fully backward compatible with v1.x code.
📖 Documentation
Comprehensive documentation is available:
- API Guide - Complete API reference
- Router Factory Usage - Detailed factory usage guide
- Logger Implementation - Custom logger guide
- Testing Guide - Local and remote test release workflows
- Examples - Code examples and patterns
- Architecture - Project structure
🏗️ Architecture
The SDK uses a modular architecture:
src/
├── factory/ # CustomRouterFactory & protocol detection
├── routers/ # Protocol-specific router implementations
│ ├── uniswap/ # Uniswap V3 & V4
│ ├── algebra/ # Algebra variants
│ └── [others]/ # Other protocol routers
├── engines/ # Quote calculation engines
├── types/ # TypeScript type definitions
└── utils/ # Utilities (logger, math, constants)Benefits:
- ✅ Clean separation of concerns
- ✅ Easy to add new protocols
- ✅ Maintainable and testable
- ✅ Tree-shakeable for smaller bundles
🔒 Security
- All calculations are performed on-chain or using verified contracts
- No private keys or sensitive data are required
- Open source and auditable
🤝 Contributing
We welcome contributions! Here's how you can help:
- Report Bugs - Open an issue with details
- Suggest Features - Share your ideas
- Submit PRs - Fix bugs or add features
- Improve Docs - Help others understand the SDK
Adding a New Protocol
- Create router in
src/routers/[protocol]/ - Add detection logic in
src/factory/protocol-detector.ts - Update factory in
src/factory/custom-router-factory.ts - Add tests and documentation
See CONTRIBUTING.md for detailed guidelines.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
Built with ❤️ by Steer Protocol
- @uniswap/v3-sdk - Uniswap V3 SDK
- @uniswap/v3-periphery - Uniswap periphery contracts
📞 Support
- Documentation: Full docs
- Issues: GitHub Issues
- Discord: Join our community
Made with ❤️ by the Steer Protocol team
