-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #94 from TalismanSociety/feat/manage-multiple-nomp…
…ools feat: support managing multiple nom pools
- Loading branch information
Showing
12 changed files
with
248 additions
and
267 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { atom, atomFamily, selectorFamily } from 'recoil' | ||
import { pjsApiSelector } from '../chains/pjs-api' | ||
import { Address } from '../../util/addresses' | ||
import { ApiPromise } from '@polkadot/api' | ||
import type { StorageKey, u32 } from '@polkadot/types' | ||
import BigNumber from 'bignumber.js' | ||
import { BN, bnToU8a, stringToU8a, u8aConcat } from '@polkadot/util' | ||
|
||
export type BondedPool = { | ||
id: number | ||
memberCounter: number | ||
points: bigint | ||
roles: { | ||
depositor: Address | ||
root: Address | ||
nominator: Address | ||
bouncer: Address | ||
} | ||
stash: Address | ||
reward: Address | ||
state: 'Open' | 'Destroying' | 'Blocked' | ||
metadata?: string | ||
} | ||
|
||
type BondedPoolRaw = { | ||
memberCounter: string | ||
points: string | ||
roles: { | ||
depositor: string | ||
root: string | ||
nominator: string | ||
bouncer: string | ||
} | ||
state: 'Open' | 'Destroying' | 'Blocked' | ||
} | ||
|
||
export const EmptyH256 = new Uint8Array(32) | ||
export const ModPrefix = stringToU8a('modl') | ||
export const U32Opts = { bitLength: 32, isLe: true } | ||
|
||
const getPoolId = (raw: StorageKey<[u32]>): number => { | ||
const idRaw = raw.toHuman() | ||
if (Array.isArray(idRaw) && idRaw[0]) { | ||
return +idRaw[0] | ||
} | ||
return 0 | ||
} | ||
|
||
const createAccount = (api: ApiPromise, poolId: BigNumber, index: number): string => { | ||
return api.registry | ||
.createType( | ||
'AccountId32', | ||
u8aConcat( | ||
ModPrefix, | ||
api.consts.nominationPools.palletId.toU8a() ?? new Uint8Array(0), | ||
new Uint8Array([index]), | ||
bnToU8a(new BN(poolId.toString()), U32Opts), | ||
EmptyH256 | ||
) | ||
) | ||
.toString() | ||
} | ||
|
||
const createAccounts = (api: ApiPromise, poolId: number) => { | ||
const poolIdBigNumber = new BigNumber(poolId) | ||
return { | ||
stash: createAccount(api, poolIdBigNumber, 0), | ||
reward: createAccount(api, poolIdBigNumber, 1), | ||
} | ||
} | ||
|
||
export const bondedPoolsAtom = atomFamily({ | ||
key: 'bondedPoolsAtom', | ||
default: selectorFamily({ | ||
key: 'bondedPoolsAtomDefault', | ||
get: | ||
(chainGenesisHash: string) => | ||
async ({ get }) => { | ||
const api = get(pjsApiSelector(chainGenesisHash)) | ||
|
||
const pools = await api.query.nominationPools.bondedPools.entries() | ||
const ids = pools.map(([key]) => getPoolId(key)) | ||
const metadata = await api.query.nominationPools.metadata.multi(ids) | ||
const metadataMulti = Object.fromEntries(metadata.map((m, i) => [ids[i], String(m.toHuman())])) | ||
|
||
return pools | ||
.map(([key, value]): BondedPool | null => { | ||
const id = getPoolId(key) | ||
|
||
const bondedPoolRaw = value.toHuman() as BondedPoolRaw | ||
const depositor = Address.fromSs58(bondedPoolRaw.roles.depositor) | ||
const root = Address.fromSs58(bondedPoolRaw.roles.root) | ||
const nominator = Address.fromSs58(bondedPoolRaw.roles.nominator) | ||
const bouncer = Address.fromSs58(bondedPoolRaw.roles.bouncer) | ||
|
||
if (id === undefined || !depositor || !root || !nominator || !bouncer) return null | ||
|
||
const { stash: stashString, reward: rewardString } = createAccounts(api, id) | ||
const stash = Address.fromSs58(stashString) | ||
const reward = Address.fromSs58(rewardString) | ||
if (!stash || !reward) return null | ||
|
||
const metadata = metadataMulti[id] | ||
|
||
const pool = { | ||
id, | ||
memberCounter: +bondedPoolRaw.memberCounter.replaceAll(',', ''), | ||
points: BigInt(bondedPoolRaw.points.replaceAll(',', '')), | ||
roles: { | ||
depositor, | ||
root, | ||
nominator, | ||
bouncer, | ||
}, | ||
stash, | ||
reward, | ||
state: bondedPoolRaw.state, | ||
metadata: metadata === '' ? undefined : metadata, | ||
} | ||
return pool | ||
}) | ||
.filter((pool): pool is BondedPool => pool !== null) | ||
}, | ||
}), | ||
}) | ||
|
||
export const selectedPoolIdAtom = atom<number | undefined>({ | ||
key: 'selectedPoolIdAtom', | ||
default: undefined, | ||
}) |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { useRecoilValueLoadable } from 'recoil' | ||
import { Address } from '@util/addresses' | ||
import { useMemo } from 'react' | ||
import { Chain } from '@domains/chains' | ||
import { bondedPoolsAtom } from '@domains/nomination-pools' | ||
|
||
/** | ||
* Returns a nom pool which the given address has a role for. | ||
* Returns undefined while loading, null if the address has no role in any pool. | ||
*/ | ||
export const useNomPoolsOf = (address: Address, chain: Chain) => { | ||
const bondedPools = useRecoilValueLoadable(bondedPoolsAtom(chain.genesisHash)) | ||
|
||
return useMemo(() => { | ||
if (bondedPools.state !== 'hasValue') return undefined | ||
return bondedPools.contents.filter(pool => { | ||
if (!pool) return false | ||
return ( | ||
pool.roles.root.isEqual(address) || | ||
pool.roles.nominator.isEqual(address) || | ||
pool.roles.depositor.isEqual(address) || | ||
pool.roles.bouncer.isEqual(address) | ||
) | ||
}) | ||
}, [address, bondedPools]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.