feat: track nomination pool members as active stakers

Add handlePoolBonded/handlePoolUnbonded handlers to Asset Hub SubQuery.
When a user bonds to a nomination pool, they are saved as an ActiveStaker
with networkId=AssetHub and stakingType=nomination-pool. This fixes the
wallet showing INACTIVE for HEZ stakers.
This commit is contained in:
2026-02-18 03:14:44 +03:00
parent 407cba9aef
commit 1c79402d5c
3 changed files with 81 additions and 0 deletions
+12
View File
@@ -34,6 +34,18 @@ dataSources:
filter:
module: nominationPools
method: PaidOut
# Pool member bonded (track active stakers)
- handler: handlePoolBonded
kind: substrate/EventHandler
filter:
module: nominationPools
method: Bonded
# Pool member unbonded (cleanup active stakers)
- handler: handlePoolUnbonded
kind: substrate/EventHandler
filter:
module: nominationPools
method: Unbonded
# Pool bonded slash
- handler: handlePoolBondedSlash
kind: substrate/EventHandler
+1
View File
@@ -4,4 +4,5 @@ export * from "./mappings/Rewards";
export * from "./mappings/PoolRewards";
export * from "./mappings/Transfers";
export * from "./mappings/NewEra";
export * from "./mappings/PoolStakers";
import "@pezkuwi/api-augment";
+68
View File
@@ -0,0 +1,68 @@
import { SubstrateEvent } from "@subql/types";
import { ActiveStaker } from "../types";
import { Option } from "@pezkuwi/types";
import {
PEZKUWI_ASSET_HUB_GENESIS,
STAKING_TYPE_NOMINATION_POOL,
} from "./constants";
/**
* Handle nominationPools.Bonded event
* Fired when a member bonds (joins or adds more) to a nomination pool.
* Creates an ActiveStaker entry for this address.
*
* Event data: [member: AccountId, pool_id: u32, bonded: Balance, joined: bool]
*/
export async function handlePoolBonded(
event: SubstrateEvent,
): Promise<void> {
const {
event: {
data: [memberEncoded],
},
} = event;
const address = memberEncoded.toString();
const stakerId = `${PEZKUWI_ASSET_HUB_GENESIS}-${STAKING_TYPE_NOMINATION_POOL}-${address}`;
const staker = ActiveStaker.create({
id: stakerId,
networkId: PEZKUWI_ASSET_HUB_GENESIS,
stakingType: STAKING_TYPE_NOMINATION_POOL,
address,
});
await staker.save();
logger.info(`Pool staker added: ${address}`);
}
/**
* Handle nominationPools.Unbonded event
* Fired when a member unbonds from a nomination pool.
* If the member has no remaining points, remove the ActiveStaker entry.
*
* Event data: [member: AccountId, pool_id: u32, balance: Balance, points: Balance, era: u32]
*/
export async function handlePoolUnbonded(
event: SubstrateEvent,
): Promise<void> {
const {
event: {
data: [memberEncoded],
},
} = event;
const address = memberEncoded.toString();
// Check if member still has points in the pool
const memberData = (await api.query.nominationPools.poolMembers(
address,
)) as Option<any>;
if (memberData.isNone || memberData.unwrap().points.toBigInt() === BigInt(0)) {
// Member fully left the pool - remove active staker
const stakerId = `${PEZKUWI_ASSET_HUB_GENESIS}-${STAKING_TYPE_NOMINATION_POOL}-${address}`;
await ActiveStaker.remove(stakerId);
logger.info(`Pool staker removed: ${address}`);
}
}