# Allowing Opengov participation for Nomination Pool members If you are a nomination pool member, you may already know that when you join a NominationPool, your funds are transferred from your account to the pooled account (in other words, you lose the ownership of these funds). We can call this `Transfer and Stake` strategy. In return, you are assigned some points which you use later to claim your funds. A side effect of this is, you cannot use your funds in the pool for governance. We had been working to fix this issue by keeping the funds held in member account itself and giving the right to stake it to the pool account ([see #3905](https://github.com/paritytech/polkadot-sdk/pull/3905)). We call this `Delegate and Stake` strategy. ## Current status This is already live on Westend (testnet). The audit identified couple of follow-up issues that I am currently addressing and expect it to be merged very soon. Once done, these changes could go live as soon as in early August on Polkadot/Kusama. ## Developer Guide ### Reading pool member's balance Use the runtime api `NominationPoolsApi_member_total_balance` that takes `AccountId` as input and returns `Balance`. ### Reading pool's balance Use the runtime api `NominationPoolsApi_pool_balance` that takes `PoolId` as input and returns `Balance`. ### Checking migration status of the pool member Use the runtime api `NominationPoolsApi_member_needs_delegate_migration` that takes `AccountId` as input, and returns `true` if user is not migrated yet. ### Apply pending slash to the member You can find more information about this in the [lazy slashes section](#Lazy-Slashes). Check if a user has pending slash by using the runtime api `NominationPoolsApi_member_pending_slash` that returns a `Balance`. If the returned value is greater than 0, the extrinsic `nominationPools.apply_slash(memberAccount)` can be dispatched. The origin is rewarded with part of the slash based on the [slash reward configuration](https://paritytech.github.io/polkadot-sdk/master/pallet_delegated_staking/pallet/trait.Config.html#associatedtype.SlashRewardFraction) of the runtime. ### Migrating a member Following conditions should pass for a member to be migrated: - Ensure either member's free balance or member's balance in the pool (`NominationPoolsApi_member_total_balance`) is above ED. - Ensure the member is not a direct staker as well. One way to do it is to check if member exists as key in the storage item `Bonded` in `pallet-staking`. Next, check if user needs to be migrated with the runtime api `NominationPoolsApi_member_needs_delegate_migration`. If it returns `true`, the extrinsic `nominationPools.migrateDelegation(memberAccount)` can be dispatched. If successful, any transaction fee would be refunded. ## User Migration Guide In most cases, a pool member don't have to do anything. Their funds would be migrated automatically by a bot script via a permissionless extrinsic. However there are cases where your migration can fail and they might need to resolve those issues before migrating. Cases where migration would fail: - If the user participates in the pool but also stake directly. Affects 646 (1.4% of pool members) accounts on Polkadot. - If the user's free balance is zero and their active contribution in the pool is lower than the existential deposit. This can happen only if there was a slash to the pool. Affects 165 accounts on Kusama, None on Polkadot. ### Dual staking Unfortunately, because of the way funds are locked, a direct staker would not be able to use the pools anymore. [More details here.](#Double-staking-issue) To be able to migrate your pool funds, following are the steps I recommend: - Unbond all your funds from staking. - Withdraw all your funds from staking after waiting for the unbonding period (7 days for Kusama, 28 days for Polkadot). - Migrate your funds. The first two steps can already be taken to avoid the migration failure when these changes are deployed on Polkadot and Kusama. ### Zero balance and lower than ED contribution if your balance is zero and your pool contribution is below [ED](https://support.polkadot.network/support/solutions/articles/65000168651-what-is-the-existential-deposit-) in the pool, you will need to top up your account before you can migrate your pool funds. ### Migrating via polkadot.js.org // TODO Integrate a way to migrate in staking dashboard and document that as well. - A pool member account can be migrated using the permissionless extrinsic `nominationPools.migrateDelegation(memberAccount)`. The fee is refunded if transaction is successful. ![image](https://hackmd.io/_uploads/H1HvFJ5P0.png) ## A detailed summary of changes for those who are curious ### High level changes After migration, the pool account becomes a `virtual staking account`. What that means is, they do not stake with their own funds, but gets delegation from other accounts. There is a new pallet into the runtime `pallet-delegated-staking` that manages all the delegation. Nomination pools uses `pallet-delegated-staking` to switch from - the older strategy of members transferring funds to pool account which is staked in `pallet-staking` - to the new way where pool members delegate funds to the pool account, and pool accounts acts as an agent of these funds to stake in `pallet-staking` as a `virtual staking account`. // TODO: try using as less new terms as possible. ### Lazy Slashes Currently whenever there is a slashing event, pool members affected are slashed eagerly. Since the funds are only in the pool account, only one account needs to be slashed per pool. With the new `DelegateStake` feature, pool funds are spread all its members and each member need to be slashed proportionally. This would be an unbounded operation therefore not feasible. Instead, with `DelegateStake`, we apply slashes to pool members lazily. Internally, we keep account of how much a pool and its members needs to be slashed. There is a permissionless extrinsic to apply any pending slash to the pool member. If successful, the caller gets part of slash as reward (if configured), incentivising free market bots to monitor and apply slashes swiftly. The advantage is, the slashing (computation) cost is spread over multiple blocks. A disadvantage is that a member might have more funds in their account locked than their actual pool contribution, which they can use to vote, until these pending slashes are applied. There is a runtime api to help with checking if a user has any pending slash `NominationPoolsApi_member_pending_slash`. ### Migration Migration happens in two stages: 1) Pool is migrated. This will happen as part of a runtime upgrade. 2) Individual pool members are migrated. This will be done through a permissionless extrinisic. #### Pool migration The following steps is what happens when a pool is migrated - The pool account is marked as Virtual Stakers in `pallet-staking`. See storage item `VirtualStakers`. - It is registered as an `Agent` in `pallet-delegation-staking`. The pallet keeps track of total funds delegated, and any pending slashes to the pool account, among other things. - All pool funds are moved to `ProxyDelegator`, a new pot account of `pallet-delegated-staking`. `ProxyDelegator` delegates back to pool account and is later used by pool members to migrate their funds into their own accounts. #### Member migration Members can migrate their funds in the pool (that temporarily exists in `ProxyDelegator`). The funds are transferred to the member account with a hold. ### Double staking issue `pallet-staking` uses the deprecated currency locks which can overlap with holds used by the pools after migration. This unfortunately means normal `stakers` (both nominators and validators) on `pallet-staking` won't be able to bond their funds in the pool. If we don't disable this, an account could potentially stake the same fund twice. For existing accounts who are both in pool and are normal stakers would need to withdraw all their funds from staking in order to migrate their delegation. In future, we will [migrate](https://github.com/paritytech/polkadot-sdk/issues/226) staking funds to use the same `holds` mechanism that is used by the pools and re-enable accounts to do both. In the meanwhile, if a user wants to do both, I suggest to use/create a separate account and use that for directly staking.