Skip to main content

Advanced Staking Features

This guide covers advanced features and calculations available in the Steer Protocol staking system.

APR Calculations

The Annual Percentage Rate (APR) calculation in Steer Protocol considers multiple factors:

// Basic APR calculation
const apr = steerClient.staking.calculateAPR(
stakingPool,
rewardTokenPrice,
totalStakedUSD
);

Components of APR Calculation

  1. Daily Emissions

    // For single reward pools
    const dailyRewardUSD = pool.dailyEmissionRewardA * rewardTokenPriceUSD;
    const baseAPR = (dailyRewardUSD * 365 * 100) / totalStakedUSD;

    // For dual reward pools
    const dailyRewardBUSD = pool.dailyEmissionRewardB * rewardTokenPriceUSD;
    const dualAPR = baseAPR + (dailyRewardBUSD * 365 * 100) / totalStakedUSD;
  2. Time-Weighted Considerations

    • Rewards are distributed linearly over time
    • APR adjusts based on remaining reward period
    • Considers periodFinish timestamp

LP Token Value Calculations

For Steer vault LP tokens, value calculation involves multiple steps:

const lpValue = await steerClient.staking.getSteerLpTokenValue({
stakingPool: pool,
amount: lpTokenAmount,
token0UsdPrice: price0,
token1UsdPrice: price1
});

Underlying Token Calculation Process

  1. Get Token Amounts

    const tokensResponse = await withdrawClient.getTokensFromLp(
    pool.staking.address,
    lpTokenAmount
    );
  2. Apply Token Prices

    const token0Value = (token0Amount * token0Price) / (10 ** token0Decimals);
    const token1Value = (token1Amount * token1Price) / (10 ** token1Decimals);
    const totalValue = token0Value + token1Value;

Total Value Locked (TVL) Calculations

Calculate the total value locked in a staking pool:

const tvl = await steerClient.staking.getTotalStakingAmountInUsd(
pool,
token0Price,
token1Price
);

TVL Calculation Process

  1. Get Total Supply

    const totalSupply = await steerClient.staking.totalSupply(poolAddress);
  2. Calculate Total Value

    const value = await steerClient.staking.getSteerLpTokenValue({
    stakingPool: pool,
    amount: totalSupply,
    token0UsdPrice,
    token1UsdPrice
    });

Transaction Preparation

For advanced integration scenarios, you can prepare transactions without executing them:

1. Prepare Stake Transaction

const stakeTx = await steerClient.staking.prepareStakeTx({
stakingPool: poolAddress,
amount: stakeAmount
});

if (stakeTx.success) {
const { address, abi, functionName, args } = stakeTx.data;
// Use these parameters with your own contract interaction logic
}

2. Prepare Withdraw Transaction

const withdrawTx = await steerClient.staking.prepareWithdrawTx({
stakingPool: poolAddress,
amount: withdrawAmount
});

3. Prepare Reward Claim Transaction

const claimTx = await steerClient.staking.prepareGetRewardTx({
stakingPool: poolAddress
});

Chain-Specific Features

Handle chain-specific requirements and validations:

// Validate chain support
const chainId = await publicClient.getChainId();
if (chainId !== pool.chainId) {
throw new Error(`Chain ID mismatch: expected ${pool.chainId}, got ${chainId}`);
}

// Get chain-specific pools
const chainPools = await steerClient.staking.getStakingPools({
chainId: 137, // Polygon
protocol: StakingProtocol.Forge
});

Error Handling and Validation

Implement comprehensive error handling:

async function safeStake(pool: StakingPool, amount: bigint) {
try {
// 1. Validate chain
const chainId = await publicClient.getChainId();
if (chainId !== pool.chainId) {
throw new Error('Invalid chain');
}

// 2. Check if pool is active
const now = Math.floor(Date.now() / 1000);
if (parseInt(pool.periodFinish) <= now) {
throw new Error('Pool expired');
}

// 3. Validate amount
const balance = await steerClient.staking.balanceOf(
pool.stakingPool,
userAddress
);
if (!balance.success) {
throw new Error('Failed to get balance');
}

// 4. Execute stake
const stakeTx = await steerClient.staking.stake({
stakingPool: pool.stakingPool,
amount
});

if (!stakeTx.success) {
throw new Error(stakeTx.error || 'Stake failed');
}

return stakeTx.data;
} catch (error) {
console.error('Stake error:', error);
throw error;
}
}

Performance Optimization

Tips for optimizing staking operations:

  1. Batch Queries

    // Get multiple pools data in parallel
    const [totalSupply, userBalance, rewards] = await Promise.all([
    steerClient.staking.totalSupply(poolAddress),
    steerClient.staking.balanceOf(poolAddress, userAddress),
    steerClient.staking.earned(poolAddress, userAddress)
    ]);
  2. Cache Pool Data

    • Cache static pool data
    • Implement refresh strategies for dynamic data
    • Use websocket subscriptions for real-time updates
  3. Efficient Filtering

    // Combine multiple filters in one call
    const filteredPools = await steerClient.staking.getStakingPools({
    chainId: 137,
    protocol: StakingProtocol.Forge,
    isLive: true,
    isDualRewards: true,
    minDailyEmissionA: 1000
    });

Best Practices

  1. Value Calculations

    • Always use proper decimal handling
    • Consider price impact for large amounts
    • Implement price feed validation
  2. Transaction Management

    • Implement proper nonce handling
    • Consider gas price strategies
    • Handle transaction replacement
  3. State Management

    • Track transaction status
    • Implement proper error recovery
    • Maintain user position history