@steerprotocol/sdk
v3.3.1
Published
Steer Protocol SDK
Readme
Steer Protocol SDK
A TypeScript SDK for interacting with Steer Protocol services.
Installation
npm install @steerprotocol/sdk viem
# or
yarn add @steerprotocol/sdk viem
# or
pnpm add @steerprotocol/sdk viemUsage
import { createPublicClient, createWalletClient, http } from 'viem';
import { mainnet } from 'viem/chains';
import { VaultClient, StakingClient } from '@steerprotocol/sdk';
// Create viem clients
const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
});
const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
});
// Initialize clients
const vaultClient = new VaultClient(publicClient, walletClient, 'production');
const stakingClient = new StakingClient(publicClient, walletClient);
// Use vault operations (including single-asset deposits)
const vaults = await vaultClient.getVaults({ chainId: 1 });
// Use staking operations
const pools = await stakingClient.getStakingPools();Supported Chains, Subgraphs, and Protocols
The SDK exposes a capabilities registry so integrators can discover supported chains and the relevant configuration (subgraph URLs, protocol availability, deployments) without enumerating enums.
import { getSupportedChains, getSupportedChainIds } from '@steerprotocol/sdk';
// Most lightweight: chains that have Steer subgraph config
const supportedChainIds = getSupportedChainIds();
// Opt in to additional details (deployments, protocol subgraphs, etc)
const supported = getSupportedChains({
include: {
subgraph: true,
deployments: true,
protocols: true,
singleAssetDeposit: true,
},
// Used for protocol-specific subgraph discovery (The Graph / Studio)
theGraphApiKey: process.env.SUBGRAPH_STUDIO_KEY ?? '',
});
for (const chain of supported) {
console.log({
chainId: chain.chainId,
chain: chain.chain,
subgraphUrl: chain.subgraphUrl,
protocolCount: chain.protocols?.length ?? 0,
features: chain.features,
});
}Available Features
- Vault Operations: Traditional vault deposits, withdrawals, and balance checking
- Single-Asset Deposits: Deposit one token and automatically balance for LP provision
- Staking: Interact with staking pools for rewards
- Pool Data: Fetch pool information and statistics
- Smart Rewards: Manage reward campaigns and claims
Staking Client
The StakingClient provides functionality for interacting with Steer Protocol staking pools. It supports both single and dual reward staking pools.
Features
- Fetch available staking pools
- Stake and withdraw tokens
- Claim rewards
- Check earned rewards and balances
- Calculate APR for staking pools
- Support for both single and dual reward pools
Example Usage
// Initialize the staking client
const stakingClient = steerClient.staking;
// Get all staking pools
const pools = await stakingClient.getStakingPools();
// Get pools for a specific chain
const polygonPools = await stakingClient.getStakingPools(137); // Polygon chain ID
// Stake tokens
await stakingClient.stake({
stakingPool: '0x...', // staking pool address
amount: 1000000000000000000n, // amount in wei
});
// Check earned rewards
const earned = await stakingClient.earned('0x...', '0x...'); // pool address, account address
console.log('Earned rewards:', earned.data);
// Calculate APR
const apr = stakingClient.calculateAPR(pool, rewardTokenPriceUSD, totalStakedUSD);Available Methods
getStakingPools(chainId?: number, protocol?: string): Fetch available staking poolsstake(params: StakeParams): Stake tokens in a poolwithdraw(params: WithdrawParams): Withdraw tokens from a poolgetReward(params: GetRewardParams): Claim rewardsearned(stakingPool: Address, account: Address): Get earned rewardstotalSupply(stakingPool: Address): Get total staked tokensbalanceOf(stakingPool: Address, account: Address): Get staked balancecalculateAPR(pool: StakingPool, rewardTokenPriceUSD: number, totalStakedUSD: number): Calculate current pool APR
Single-Asset Deposit
The Single-Asset Deposit feature allows users to deposit only one token (token0 or token1) into a liquidity vault, while the contract internally performs a swap to balance the token pair before depositing into the vault. This eliminates the need for users to provide both tokens in the correct ratio.
Features
- Single Token Input: Deposit only token0 or token1 instead of both
- Automatic Balancing: Internal swap to achieve the correct token ratio
- Slippage Protection: Configurable slippage limits for both swap and deposit
- Preview Functionality: Simulate the entire process before execution
- Modular Architecture: Each step is separately testable and reusable
- Multiple AMM Support: Currently supports UniswapV3, extensible for other AMMs
- Comprehensive Error Handling: Detailed error messages and validation
How It Works
The single-asset deposit process follows these steps:
- Calculate Swap Amount: Determine how much of the input token needs to be swapped
- Calculate Limit Price: Apply slippage protection using current pool price
- Simulate Swap: Preview the swap results without executing
- Estimate LP Tokens: Calculate expected LP token output
- Execute Deposit: Submit the transaction with all parameters
Quick Start
import { VaultClient, AMMType } from '@steerprotocol/sdk';
import { createPublicClient, createWalletClient, http, parseEther } from 'viem';
import { mainnet } from 'viem/chains';
// Setup clients
const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
});
const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
});
// Initialize vault client
const vaultClient = new VaultClient(publicClient, walletClient, 'production');
// Preview single-asset deposit
const preview = await vaultClient.previewSingleAssetDeposit(
{
assets: parseEther('100'), // 100 tokens to deposit
receiver: userAddress, // Address to receive LP tokens
vault: vaultAddress, // Vault contract address
isToken0: true, // Depositing token0
depositSlippagePercent: 5n, // 5% max slippage for deposit
swapSlippageBP: 500, // 5% slippage for internal swap (in basis points)
ammType: AMMType.UniswapV3, // AMM type
singleAssetDepositContract: contractAddress, // Single-asset deposit contract
},
poolAddress
);
if (preview.success) {
console.log('Expected LP tokens:', preview.data.lpEstimation.lpTokens);
console.log('Amount to be swapped:', preview.data.swapAmount);
console.log('Final token0 amount:', preview.data.lpEstimation.finalAmount0);
console.log('Final token1 amount:', preview.data.lpEstimation.finalAmount1);
// Execute the deposit
const result = await vaultClient.singleAssetDeposit({
assets: parseEther('100'),
receiver: userAddress,
vault: vaultAddress,
isToken0: true,
depositSlippagePercent: 5n,
swapSlippageBP: 500,
ammType: AMMType.UniswapV3,
singleAssetDepositContract: contractAddress,
});
if (result.success) {
console.log('Transaction hash:', result.data);
}
}Block-pinned vault execution context
Strategy execution consumers can read a normalized, JSON-safe vault context without selecting protocol adapters or assembling pool state themselves:
import { getVaultExecutionContext } from '@steerprotocol/sdk';
const context = await getVaultExecutionContext({
publicClient,
vaultAddress: '0x666805942995ff8494294720a1dadb7cd2348750',
blockNumber: 49_251_269n,
epochTimestamp: 1_800_000_000n, // Unix seconds; explicit, never wall-clock time
});
if (!context.success) throw new Error(context.error);
console.log(context.data.protocol, context.data.currentTick);
console.log(context.data.totalAmount0, context.data.lastExecutionTimeSeconds);The same capability is available as vaultClient.getExecutionContext(...). The SDK resolves the
vault's beacon name, beacon address, and protocol through the deployed VaultRegistry, verifies
non-v4 pool factories against SDK protocol configuration, and reads positions, totals, tick spacing,
and pool state at the exact supplied block. Uniswap v4 uses the vault's complete poolKey(), derives
its pool ID, and reads state through the configured StateView; an optional poolKey input acts as
an assertion and must match exactly.
All integer values that may exceed JavaScript's safe range are returned as decimal strings. The
provenance object identifies block-pinned contract data. Last execution comes from the established
Steer vaultSnapshots entity, queried below both the explicit epoch and pinned-block timestamp; its
provenance is marked timestamp-bounded because the entity does not expose a block number. When no
earlier snapshot exists, both last-execution fields are null; lookup or historical consistency
failures return an unsuccessful SteerResponse rather than falling back to latest state.
Advanced Usage
Using Individual Functions
Each step can be used independently for testing or custom implementations:
import {
calculateSwapAmount,
calculateLimitPrice,
simulateSwap,
estimateLpTokens,
AMMType,
} from '@steerprotocol/sdk';
// Step 1: Calculate swap amount
const swapResult = await calculateSwapAmount(publicClient, {
depositAmount: parseEther('100'),
isToken0: true,
vault: vaultAddress,
pool: poolAddress,
ammType: AMMType.UniswapV3,
singleAssetDepositContract: contractAddress,
});
// Step 2: Calculate price limit for slippage protection
const limitPrice = await calculateLimitPrice(publicClient, {
pool: poolAddress,
slippageBP: 500,
zeroForOne: true,
ammType: AMMType.UniswapV3,
});
// Step 3: Simulate the swap
const simulation = await simulateSwap(
publicClient,
{
pool: poolAddress,
recipient: userAddress,
zeroForOne: true,
amountSpecified: parseEther('10'),
sqrtPriceLimitX96: limitPrice,
ammType: AMMType.UniswapV3,
tokenIn: '0x...', // Token being swapped from
tokenOut: '0x...', // Token being swapped to
fee: 3000, // Pool fee in basis points
},
137
); // Chain ID (e.g., 137 for Polygon)
// Step 4: Estimate LP tokens
const estimation = await estimateLpTokens(publicClient, {
vault: vaultAddress,
originalAssets: parseEther('100'),
swapAmount: swapResult.data.swapAmount,
swapResult: simulation.data,
isToken0: true,
});Using the SingleAssetDepositClient Directly
import { SingleAssetDepositClient } from '@steerprotocol/sdk';
const client = new SingleAssetDepositClient(publicClient, walletClient);
// Preview deposit
const preview = await client.previewDeposit(params, poolAddress);
// Prepare transaction (without executing)
const preparedTx = await client.prepareDepositTx(params);
// Validate parameters
client.validateDepositParams(params);Supported AMM Types
enum AMMType {
UniswapV3 = 0, // ✅ Fully implemented
Algebra = 1, // 🚧 Planned
AlgebraDirectional = 2, // 🚧 Planned
AlgebraVE33 = 3, // 🚧 Planned
AlgebraIntegral = 4, // 🚧 Planned
}Currently, only UniswapV3 is fully implemented. Other AMM types will be added in future releases.
Error Handling
All functions return a consistent SteerResponse<T> format:
interface SteerResponse<T> {
data: T | null;
status: number;
success: boolean;
error?: string;
}
// Example error handling
const result = await vaultClient.previewSingleAssetDeposit(params, poolAddress);
if (!result.success) {
console.error('Preview failed:', result.error);
return;
}
// Use result.data safely
console.log('LP tokens:', result.data.lpEstimation.lpTokens);Common Error Cases
- Invalid AMM Type: Only UniswapV3 is currently supported
- Insufficient Liquidity: Pool doesn't have enough liquidity for the swap
- Slippage Too High: Price moved beyond acceptable limits
- Invalid Addresses: Zero addresses or invalid contract addresses
- Amount Too Small: Deposit amount too small to process
Testing
Each function is designed to be independently testable:
import { calculateSwapAmount, AMMType } from '@steerprotocol/sdk';
describe('Single-Asset Deposit', () => {
it('should calculate correct swap amount', async () => {
const result = await calculateSwapAmount(publicClient, {
depositAmount: parseEther('100'),
isToken0: true,
vault: vaultAddress,
pool: poolAddress,
ammType: AMMType.UniswapV3,
singleAssetDepositContract: contractAddress,
});
expect(result.success).toBe(true);
expect(result.data.swapAmount).toBeGreaterThan(0n);
});
});Configuration Parameters
| Parameter | Type | Description |
| ---------------------------- | --------- | ----------------------------------------- |
| assets | bigint | Amount of input token to deposit |
| receiver | Address | Address to receive LP tokens |
| vault | Address | Vault contract address |
| isToken0 | boolean | true for token0, false for token1 |
| depositSlippagePercent | bigint | Max slippage for deposit (in %) |
| swapSlippageBP | number | Slippage for internal swap (basis points) |
| ammType | AMMType | Type of AMM (currently UniswapV3) |
| singleAssetDepositContract | Address | Single-asset deposit contract address |
Architecture
The module is built with a modular architecture where each step is a separate, testable function:
src/base/vault/single-asset/
├── types.ts # TypeScript interfaces and enums
├── calculateSwapAmount.ts # Step 1: Calculate swap amount
├── calculateLimitPrice.ts # Step 2: Calculate slippage protection
├── simulateSwap.ts # Step 3: Simulate swap execution
├── estimateLpTokens.ts # Step 4: Estimate LP token output
├── singleAssetDeposit.ts # Main orchestrator client
└── index.ts # Exports everythingThis design allows for:
- Individual Testing: Each function can be unit tested separately
- Reusability: Functions can be used in different contexts
- Maintainability: Easy to update or extend individual components
- Debugging: Easy to isolate issues to specific steps
Requirements
- Node.js >= 18.0.0
- viem >= 2.22.0
Development
- Install dependencies:
npm install- Build the package:
npm run build- Run tests:
npm test- Format code:
npm run format- Lint code:
npm run lintTroubleshooting
CommonJS/ESM Import Issues
If you encounter the following error:
import { SteerClient } from "@steerprotocol/sdk";
^^^^^^^^^^^
SyntaxError: Named export 'SteerClient' not found. The requested module '@steerprotocol/sdk' is a CommonJS module...Add the following to your tsconfig.json:
{
"compilerOptions": {
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}License
MIT
