Skip to main content

Overview

The EarningService manages all earning-related functionality including native staking, liquid staking, nomination pools, and lending across multiple blockchain networks. It provides a unified interface for yield generation activities.

Key Features

  • Native staking (relay chains, parachains)
  • Liquid staking pools (Bifrost, Acala, Parallel)
  • Nomination pools
  • Lending protocols
  • Staking reward tracking
  • Validator selection and management
  • Unstaking and withdrawal management

Class: EarningService

Constructor

constructor(state: KoniState)
state
KoniState
required
The global state object of the extension

Lifecycle Methods

init()

Initializes the earning service and loads data.
async init(): Promise<void>

start()

Starts the earning service and begins tracking positions.
async start(): Promise<void>

stop()

Stops the earning service.
async stop(): Promise<void>

Pool Information Methods

getYieldPoolInfo()

Retrieves all available yield pools.
async getYieldPoolInfo(): Promise<YieldPoolInfo[]>
Returns:
YieldPoolInfo[]
array
Array of available yield pools with metadata and statistics
Usage:
const pools = await earningService.getYieldPoolInfo();
pools.forEach(pool => {
  console.log(`${pool.name}: APY ${pool.statistic?.assetEarning[0]?.apy}%`);
});

getYieldPool()

Retrieves a specific yield pool by slug.
async getYieldPool(slug: string): Promise<YieldPoolInfo | undefined>
slug
string
required
Pool identifier (e.g., ‘DOT___native_staking___polkadot’)

subscribeYieldPoolInfo()

Subscribes to yield pool updates.
subscribeYieldPoolInfo(): BehaviorSubject<Record<string, YieldPoolInfo>>
Returns:
BehaviorSubject
BehaviorSubject
Observable that emits pool information updates

Position Management Methods

getYieldPositionInfo()

Retrieves all staking positions for the current account.
async getYieldPositionInfo(): Promise<YieldPositionInfo[]>
Returns:
YieldPositionInfo[]
array
Array of staking positions with balances and status

getYieldPosition()

Retrieves a specific position for an address and pool.
async getYieldPosition(
  address: string,
  slug: string
): Promise<YieldPositionInfo | undefined>
address
string
required
Wallet address
slug
string
required
Pool slug

subscribeYieldPosition()

Subscribes to position updates.
subscribeYieldPosition(): BehaviorSubject<YieldPositionInfo[]>

Reward Methods

subscribeEarningReward()

Subscribes to staking reward updates.
subscribeEarningReward(): BehaviorSubject<EarningRewardJson>
Returns:
BehaviorSubject
BehaviorSubject
Observable emitting current claimable rewards
Usage:
earningService.subscribeEarningReward().subscribe((rewards) => {
  Object.values(rewards.data).forEach(reward => {
    console.log(`Unclaimed: ${reward.unclaimedReward} ${reward.slug}`);
  });
});

subscribeEarningRewardHistory()

Subscribes to historical earning rewards.
subscribeEarningRewardHistory(): BehaviorSubject<Record<string, EarningRewardHistoryItem>>

Pool Target Methods

getPoolTargets()

Retrieves available validators/targets for a pool.
async getPoolTargets(slug: string): Promise<YieldPoolTarget[]>
slug
string
required
Pool slug
Returns:
YieldPoolTarget[]
array
Array of available validators with metadata
address
string
Validator address
identity
string
Validator identity/name
totalStake
string
Total stake on validator
commission
number
Validator commission rate
expectedReturn
number
Expected APY
Usage:
const validators = await earningService.getPoolTargets('DOT___native_staking___polkadot');
validators.forEach(v => {
  console.log(`${v.identity}: ${v.expectedReturn}% APY, ${v.commission}% commission`);
});

Staking Action Methods

earlyValidateJoin()

Validates joining a pool before creating the transaction.
async earlyValidateJoin(
  request: RequestEarlyValidateYield
): Promise<ResponseEarlyValidateYield>
request
RequestEarlyValidateYield
required
Validation request parameters
slug
string
required
Pool slug
address
string
required
Staker address
amount
string
required
Amount to stake
Returns:
ResponseEarlyValidateYield
object
Validation response with errors or warnings

handleYieldJoin()

Handles the staking join process.
async handleYieldJoin(
  params: HandleYieldStepParams
): Promise<HandleYieldStepData>
params
HandleYieldStepParams
required
Join parameters including pool, amount, and validators
Returns:
HandleYieldStepData
object
Transaction data for the staking operation

handleYieldLeave()

Handles unstaking from a pool.
async handleYieldLeave(
  params: RequestYieldLeave
): Promise<[ExtrinsicType, TransactionData]>
params
RequestYieldLeave
required
Unstaking parameters
slug
string
required
Pool slug
address
string
required
Staker address
amount
string
required
Amount to unstake
fastLeave
boolean
Whether to use fast unstake if available

handleYieldWithdraw()

Withdraws unstaked funds after the unbonding period.
async handleYieldWithdraw(
  params: RequestYieldWithdrawal
): Promise<TransactionData>

handleYieldClaimReward()

Claims accumulated staking rewards.
async handleYieldClaimReward(
  params: RequestStakeClaimReward
): Promise<TransactionData>
params
RequestStakeClaimReward
required
Claim parameters
slug
string
required
Pool slug
address
string
required
Staker address
bondReward
boolean
Whether to bond rewards instead of claiming

Data Types

YieldPoolInfo

interface YieldPoolInfo {
  slug: string;
  name: string;
  chain: string;
  type: YieldPoolType;
  group: string;
  metadata: {
    description: string;
    shortName: string;
    logo?: string;
    inputAsset: string;
    derivativeAssets?: string[];
    availableMethod: {
      join: boolean;
      defaultUnstake: boolean;
      fastUnstake: boolean;
      cancelUnstake: boolean;
      withdraw: boolean;
      claimReward: boolean;
    };
  };
  statistic?: {
    assetEarning: Array<{
      slug: string;
      apy: number;
    }>;
    tvl: string;
    totalApy: number;
  };
}

YieldPositionInfo

interface YieldPositionInfo {
  slug: string;
  chain: string;
  address: string;
  balanceToken: string;
  activeStake: string;
  unstaking: string;
  status: EarningStatus;
  nominations: Array<{
    validatorAddress: string;
    validatorIdentity?: string;
    activeStake: string;
  }>;
}

YieldPoolType

enum YieldPoolType {
  NATIVE_STAKING = 'NATIVE_STAKING',
  NOMINATION_POOL = 'NOMINATION_POOL',
  LIQUID_STAKING = 'LIQUID_STAKING',
  LENDING = 'LENDING'
}

Example: Complete Staking Flow

import EarningService from '@subwallet/extension-base/services/earning-service';

// Initialize
const earningService = new EarningService(state);
await earningService.init();
await earningService.start();

// 1. Get available pools
const pools = await earningService.getYieldPoolInfo();
const polkadotPool = pools.find(p => p.chain === 'polkadot' && p.type === YieldPoolType.NATIVE_STAKING);

// 2. Get validators
const validators = await earningService.getPoolTargets(polkadotPool.slug);
const topValidators = validators.slice(0, 16); // Select top 16

// 3. Validate before staking
const validation = await earningService.earlyValidateJoin({
  slug: polkadotPool.slug,
  address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  amount: '10000000000' // 1 DOT (10 decimals)
});

if (validation.passed) {
  // 4. Create staking transaction
  const result = await earningService.handleYieldJoin({
    data: {
      slug: polkadotPool.slug,
      address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
      amount: '10000000000',
      selectedValidators: topValidators.map(v => v.address)
    },
    path: {}, // Optimal path
    currentStep: 0
  });
  
  console.log('Staking transaction ready:', result);
}

// 5. Monitor position
earningService.subscribeYieldPosition().subscribe((positions) => {
  const myPosition = positions.find(p => 
    p.address === '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
  );
  
  if (myPosition) {
    console.log('Active stake:', myPosition.activeStake);
    console.log('Nominations:', myPosition.nominations.length);
  }
});

// 6. Monitor rewards
earningService.subscribeEarningReward().subscribe((rewards) => {
  const myReward = Object.values(rewards.data).find(r => 
    r.address === '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
  );
  
  if (myReward && parseFloat(myReward.unclaimedReward) > 0) {
    console.log('Claimable rewards:', myReward.unclaimedReward);
  }
});

Supported Protocols

Native Staking

  • Polkadot, Kusama (Relay chains)
  • Astar, Moonbeam (Parachains)
  • Bittensor (TAO)

Nomination Pools

  • Polkadot, Kusama
  • Asset Hub (Statemint/Statemine)

Liquid Staking

  • Bifrost (vDOT, vKSM)
  • Acala (LDOT)
  • Parallel (sDOT)
  • StellaSwap

Lending

  • Interlay (iBTC)

Build docs developers (and LLMs) love