Skip to content

Commit

Permalink
Made some components and selectors more general so they work with any…
Browse files Browse the repository at this point in the history
… kind of account. Also added wallet page to show balances of any address.
  • Loading branch information
NoahSaso committed Oct 21, 2023
1 parent 33d4444 commit b66cf52
Show file tree
Hide file tree
Showing 35 changed files with 641 additions and 401 deletions.
20 changes: 20 additions & 0 deletions apps/dapp/pages/wallet/[chain]/[address]/[[...tab]].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// GNU AFFERO GENERAL PUBLIC LICENSE Version 3. Copyright (C) 2022 DAO DAO Contributors.
// See the "LICENSE" file in the root directory of this package for more copyright information.

import { GetStaticPaths, GetStaticProps } from 'next'

import { serverSideTranslations } from '@dao-dao/i18n/serverSideTranslations'
import { Wallet } from '@dao-dao/stateful'

export default Wallet

export const getStaticProps: GetStaticProps = async ({ locale }) => ({
props: {
...(await serverSideTranslations(locale, ['translation'])),
},
})

export const getStaticPaths: GetStaticPaths = () => ({
paths: [],
fallback: true,
})
1 change: 1 addition & 0 deletions packages/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@
"correctErrorsAbove": "Please correct the errors above.",
"couldntFindDAO": "We couldn't find a DAO with that address.",
"couldntFindProposal": "We couldn't find a proposal with that ID.",
"couldntFindWallet": "We couldn't find a wallet with that address.",
"counterpartyBalanceInsufficient": "The counterparty's balance of {{amount}} ${{tokenSymbol}} is insufficient. They may be unable to complete this swap.",
"daoAccountNotFound": "The DAO account could not be found for this chain.",
"daoAndSubDaosAlreadyOnV2": "This DAO (and all of its SubDAOs, if it has any) have already been upgraded.",
Expand Down
168 changes: 168 additions & 0 deletions packages/state/recoil/selectors/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import {
constSelector,
selectorFamily,
waitForAll,
waitForAllSettled,
} from 'recoil'

import {
Account,
AccountType,
GenericTokenBalance,
WithChainId,
} from '@dao-dao/types'

import { isDaoSelector } from './contract'
import { DaoCoreV2Selectors } from './contracts'
import {
genericTokenBalancesSelector,
genericTokenDelegatedBalanceSelector,
} from './token'
import { valenceAccountsSelector } from './valence'

// Get accounts controlled by this address, including its native chain, all
// polytone proxies, and all valence accounts.
export const accountsSelector = selectorFamily<
Account[],
WithChainId<{ address: string }>
>({
key: 'accounts',
get:
({ chainId, address }) =>
({ get }) => {
const isDao = get(
isDaoSelector({
chainId,
address,
})
)

const polytoneProxies = isDao
? Object.entries(
get(
DaoCoreV2Selectors.polytoneProxiesSelector({
chainId,
contractAddress: address,
})
)
)
: []

const allAccounts: Account[] = [
// Current chain.
{
chainId,
address,
type: AccountType.Native,
},
// Polytone.
...polytoneProxies.map(
([chainId, address]): Account => ({
chainId,
address,
type: AccountType.Polytone,
})
),
]

// Get valence accounts on each potential chain.
const valenceAccounts = get(
waitForAll(
allAccounts.map(({ chainId, address }) =>
valenceAccountsSelector({
address,
chainId,
})
)
)
).flat()

// Add valence accounts.
allAccounts.push(...valenceAccounts)

return allAccounts
},
})

export const allBalancesSelector = selectorFamily<
// Map chain ID to token balances on that chain.
Record<string, GenericTokenBalance[]>,
WithChainId<{
address: string
// If account is a DAO, set this to the address of its governance token.
cw20GovernanceTokenAddress?: string
}>
>({
key: 'allBalances',
get:
({ address, cw20GovernanceTokenAddress, chainId }) =>
({ get }) => {
const isDao = get(
isDaoSelector({
chainId,
address,
})
)

const allAccounts = get(
accountsSelector({
chainId,
address,
})
)

// Neutron's modified DAOs do not support cw20s, so this may error. Ignore
// if so.
const cw20BalancesLoadable = get(
waitForAllSettled(
isDao
? [
DaoCoreV2Selectors.allCw20TokensWithBalancesSelector({
contractAddress: address,
chainId,
governanceTokenAddress: cw20GovernanceTokenAddress,
}),
]
: [constSelector([])]
)
)[0]

const allBalances = [
// Native balances.
...get(
waitForAll(
allAccounts.flatMap(({ address, chainId }) => [
// All unstaked
genericTokenBalancesSelector({
chainId,
address,
}),
// Native staked
genericTokenDelegatedBalanceSelector({
chainId,
walletAddress: address,
}),
])
)
).flat(),
// Cw20s on native chain.
...(cw20BalancesLoadable.state === 'hasValue'
? cw20BalancesLoadable.contents
: []),
]

const uniqueChainIds = [
...new Set(allAccounts.map(({ chainId }) => chainId)),
]

return uniqueChainIds.reduce(
(acc, chainId) => ({
...acc,
[chainId]: allBalances.filter(
({ token }) => token.chainId === chainId
),
}),
{} as Record<string, GenericTokenBalance[]>
)
},
})
33 changes: 32 additions & 1 deletion packages/state/recoil/selectors/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { fromUtf8, toUtf8 } from '@cosmjs/encoding'
import { selectorFamily } from 'recoil'

import { ContractVersion, InfoResponse, WithChainId } from '@dao-dao/types'
import { parseContractVersion } from '@dao-dao/utils'
import {
getChainForChainId,
isValidContractAddress,
parseContractVersion,
} from '@dao-dao/utils'

import {
blockHeightTimestampSafeSelector,
Expand Down Expand Up @@ -198,3 +202,30 @@ export const isContractSelector = selectorFamily<
}
},
})

export const isDaoSelector = selectorFamily<
boolean,
WithChainId<{ address: string }>
>({
key: 'isDao',
get:
({ address, chainId }) =>
({ get }) =>
isValidContractAddress(
address,
getChainForChainId(chainId).bech32_prefix
) &&
get(
isContractSelector({
contractAddress: address,
chainId,
names: [
// V1
'cw-core',
// V2
'cwd-core',
'dao-core',
],
})
),
})
52 changes: 0 additions & 52 deletions packages/state/recoil/selectors/contracts/DaoCore.v2.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { selectorFamily, waitForAll, waitForAny } from 'recoil'

import {
Account,
AccountType,
GenericTokenBalance,
PolytoneProxies,
TokenType,
Expand Down Expand Up @@ -54,7 +52,6 @@ import {
import { cosmWasmClientForChainSelector } from '../chain'
import { queryContractIndexerSelector } from '../indexer'
import { genericTokenSelector } from '../token'
import { valenceAccountsSelector } from '../valence'
import * as Cw20BaseSelectors from './Cw20Base'

type QueryClientParams = WithChainId<{
Expand Down Expand Up @@ -1235,52 +1232,3 @@ export const coreAddressForPolytoneProxySelector = selectorFamily<
})
),
})

// Get all accounts controlled by this DAO, including its native chain, all
// polytone proxies, and all valence accounts.
export const allAccountsSelector = selectorFamily<Account[], QueryClientParams>(
{
key: 'daoCoreV2AllAccounts',
get:
(queryClientParams) =>
({ get }) => {
const polytoneProxies = Object.entries(
get(polytoneProxiesSelector(queryClientParams))
)

const allAccounts: Account[] = [
// Current chain.
{
chainId: queryClientParams.chainId,
address: queryClientParams.contractAddress,
type: AccountType.Native,
},
// Polytone.
...polytoneProxies.map(
([chainId, address]): Account => ({
chainId,
address,
type: AccountType.Polytone,
})
),
]

// Get valence accounts on each potential chain.
const valenceAccounts = get(
waitForAll(
allAccounts.map(({ chainId, address }) =>
valenceAccountsSelector({
address,
chainId,
})
)
)
).flat()

// Add valence accounts.
allAccounts.push(...valenceAccounts)

return allAccounts
},
}
)
1 change: 1 addition & 0 deletions packages/state/recoil/selectors/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './contracts'

export * from './account'
export * from './chain'
export * from './contract'
export * from './discord'
Expand Down
13 changes: 3 additions & 10 deletions packages/state/recoil/selectors/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
nativeBalancesSelector,
nativeDelegatedBalanceSelector,
} from './chain'
import { isContractSelector } from './contract'
import { isDaoSelector } from './contract'
import { Cw20BaseSelectors, DaoCoreV2Selectors } from './contracts'
import {
osmosisDenomForTokenSelector,
Expand Down Expand Up @@ -245,16 +245,9 @@ export const genericTokenBalancesSelector = selectorFamily<
) &&
// If is a DAO contract.
get(
isContractSelector({
contractAddress: address,
isDaoSelector({
address,
chainId,
names: [
// V1
'cw-core',
// V2
'cwd-core',
'dao-core',
],
})
)
? [
Expand Down
Loading

0 comments on commit b66cf52

Please sign in to comment.