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