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)
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>
getYieldPoolInfo()
Retrieves all available yield pools.
async getYieldPoolInfo(): Promise<YieldPoolInfo[]>
Returns:
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>
Pool identifier (e.g., ‘DOT___native_staking___polkadot’)
subscribeYieldPoolInfo()
Subscribes to yield pool updates.
subscribeYieldPoolInfo(): BehaviorSubject<Record<string, YieldPoolInfo>>
Returns:
Observable that emits pool information updates
Position Management Methods
getYieldPositionInfo()
Retrieves all staking positions for the current account.
async getYieldPositionInfo(): Promise<YieldPositionInfo[]>
Returns:
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>
subscribeYieldPosition()
Subscribes to position updates.
subscribeYieldPosition(): BehaviorSubject<YieldPositionInfo[]>
Reward Methods
subscribeEarningReward()
Subscribes to staking reward updates.
subscribeEarningReward(): BehaviorSubject<EarningRewardJson>
Returns:
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[]>
Returns:
Array of available validators with metadataValidator commission rate
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
Returns:
ResponseEarlyValidateYield
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:
Transaction data for the staking operation
handleYieldLeave()
Handles unstaking from a pool.
async handleYieldLeave(
params: RequestYieldLeave
): Promise<[ExtrinsicType, TransactionData]>
params
RequestYieldLeave
required
Unstaking parametersWhether 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 parametersWhether 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