Skip to content

Commit

Permalink
Detect native denoms fully staked in daos (#1714)
Browse files Browse the repository at this point in the history
  • Loading branch information
ismellike authored Feb 21, 2024
1 parent dcc5b5e commit 136a14e
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 2 deletions.
6 changes: 6 additions & 0 deletions packages/config/eslint/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ const eslintConfig = {
'no-unused-vars': ['off'],
'react/jsx-sort-props': ['warn', { reservedFirst: ['key'] }],
'tailwindcss/classnames-order': ['warn'],
'prettier/prettier': [
'error',
{
endOfLine: 'auto',
},
],
eqeqeq: ['error'],
},
overrides: [
Expand Down
27 changes: 25 additions & 2 deletions packages/state/recoil/selectors/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { fromBase64, toHex } from '@cosmjs/encoding'
import { Coin, IndexedTx, StargateClient } from '@cosmjs/stargate'
import uniq from 'lodash.uniq'
import {
noWait,
selector,
selectorFamily,
waitForAll,
Expand Down Expand Up @@ -78,6 +79,7 @@ import {
queryValidatorIndexerSelector,
} from './indexer'
import { genericTokenSelector } from './token'
import { walletTokenDaoStakedDenomsSelector } from './wallet'

export const stargateClientForChainSelector = selectorFamily<
StargateClient,
Expand Down Expand Up @@ -342,15 +344,36 @@ export const nativeBalancesSelector = selectorFamily<
const balances = [
...get(justNativeBalancesSelector({ address, chainId })),
]
// Add native denom if not present.
const nativeToken = getNativeTokenForChainId(chainId)
if (!balances.some(({ denom }) => denom === nativeToken.denomOrAddress)) {
const stakedDenoms =
get(
noWait(
walletTokenDaoStakedDenomsSelector({
walletAddress: address,
chainId,
})
)
).valueMaybe() || []

const uniqueDenoms = new Set(balances.map(({ denom }) => denom))

// Add native denom if not present.
if (!uniqueDenoms.has(nativeToken.denomOrAddress)) {
balances.push({
amount: '0',
denom: nativeToken.denomOrAddress,
})
uniqueDenoms.add(nativeToken.denomOrAddress)
}

// Add denoms staked to DAOs if not present.
stakedDenoms.forEach((denom) => {
if (!uniqueDenoms.has(denom)) {
balances.push({ amount: '0', denom })
uniqueDenoms.add(denom)
}
})

const tokenLoadables = get(
waitForAny(
balances.map(({ denom }) =>
Expand Down
1 change: 1 addition & 0 deletions packages/state/recoil/selectors/indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export const queryValidatorIndexerSelector = selectorFamily<
})
),
})

export const queryWalletIndexerSelector = selectorFamily<
any,
Omit<QueryIndexerParams, 'type' | 'address'> & {
Expand Down
70 changes: 70 additions & 0 deletions packages/state/recoil/selectors/wallet.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { selectorFamily, waitForAll } from 'recoil'

import { GenericTokenBalance, TokenType, WithChainId } from '@dao-dao/types'
import { DAO_VOTING_TOKEN_STAKED_CONTRACT_NAMES } from '@dao-dao/utils'

import { refreshWalletBalancesIdAtom } from '../atoms'
import { isContractSelector } from './contract'
import { votingModuleSelector } from './contracts/DaoCore.v2'
import * as DaoVotingTokenStaked from './contracts/DaoVotingTokenStaked'
import { queryWalletIndexerSelector } from './indexer'
import { genericTokenSelector } from './token'

Expand Down Expand Up @@ -50,3 +54,69 @@ export const walletCw20BalancesSelector = selectorFamily<
}))
},
})

export const walletTokenDaoStakedDenomsSelector = selectorFamily<
readonly string[],
WithChainId<{ walletAddress: string }>
>({
key: 'walletTokenDaoStakedDenoms',
get:
({ walletAddress, chainId }) =>
({ get }) => {
// Get the DAOs that the wallet is a member of
const daos = get(
queryWalletIndexerSelector({
chainId,
walletAddress,
formula: 'daos/memberOf',
})
)
if (!daos || !Array.isArray(daos) || daos.length === 0) {
return []
}

// Get the token staked voting modules for each DAO
const votingModules = get(
waitForAll(
daos.map(({ dao: contractAddress }) =>
votingModuleSelector({
contractAddress,
chainId,
params: [],
})
)
)
).filter((contractAddress) =>
get(
isContractSelector({
contractAddress,
chainId,
names: DAO_VOTING_TOKEN_STAKED_CONTRACT_NAMES,
})
)
)

if (votingModules.length === 0) {
return []
}

// Get a list of denoms from the voting modules
const denoms = get(
waitForAll(
votingModules.map((contractAddress) =>
DaoVotingTokenStaked.denomSelector({
contractAddress,
chainId,
params: [],
})
)
)
)

// Create a Set from the denoms to ensure uniqueness
const uniqueDenoms = new Set(denoms.map(({ denom }) => denom))

// Convert the Set back into an array to return
return [...uniqueDenoms]
},
})

0 comments on commit 136a14e

Please sign in to comment.