Skip to content

Commit

Permalink
Recognize when a DAO admin is a chain module account and show gov as …
Browse files Browse the repository at this point in the history
…parent DAO. (#1368)
  • Loading branch information
NoahSaso authored Sep 7, 2023
1 parent 81f110c commit e02c228
Show file tree
Hide file tree
Showing 9 changed files with 287 additions and 123 deletions.
15 changes: 15 additions & 0 deletions packages/state/recoil/selectors/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
} from '@dao-dao/types'
import {
MAINNET,
addressIsModule,
cosmWasmClientRouter,
cosmosSdkVersionIs47OrHigher,
cosmosValidatorToValidator,
Expand Down Expand Up @@ -890,6 +891,20 @@ export const moduleNameForAddressSelector = selectorFamily<
},
})

// Check whether or not the address is a module account.
export const addressIsModuleSelector = selectorFamily<
boolean,
WithChainId<{ address: string }>
>({
key: 'addressIsModule',
get:
({ address, chainId }) =>
async ({ get }) => {
const client = get(cosmosRpcClientForChainSelector(chainId))
return await addressIsModule(client, address)
},
})

// Get bonded and unbonded tokens. Bonded tokens represent all possible
// governance voting power.
export const chainStakingPoolSelector = selectorFamily<Pool, WithChainId<{}>>({
Expand Down
179 changes: 104 additions & 75 deletions packages/stateful/recoil/selectors/dao/cards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { RecoilValueReadOnly, selectorFamily, waitForAll } from 'recoil'

import {
DaoCoreV2Selectors,
addressIsModuleSelector,
contractInstantiateTimeSelector,
contractVersionSelector,
daoTvlSelector,
Expand All @@ -25,7 +26,10 @@ import {
} from '@dao-dao/types/contracts/DaoCore.v2'
import {
getChainForChainId,
getDisplayNameForChainId,
getFallbackImage,
getImageUrlForChainId,
getSupportedChainConfig,
isValidContractAddress,
parseContractVersion,
} from '@dao-dao/utils'
Expand Down Expand Up @@ -77,27 +81,99 @@ export const daoCardInfoSelector = selectorFamily<
if (
admin &&
// A DAO without a parent DAO may be its own admin.
admin !== coreAddress &&
// Ensure address is a contract.
isValidContractAddress(admin, getChainForChainId(chainId).bech32_prefix)
admin !== coreAddress
) {
// Indexer may return `adminInfo`, in which case don't query again. If
// null, there is no admin to load. Otherwise. If not null, query chain.
if ('adminInfo' in dumpedState) {
const { adminInfo } = dumpedState as IndexerDumpState
if (adminInfo) {
const {
admin: adminAdmin,
info,
config: { name, image_url },
registeredSubDao = false,
} = adminInfo
const coreVersion = info && parseContractVersion(info.version)
if (
// If address is a DAO contract.
isValidContractAddress(
admin,
getChainForChainId(chainId).bech32_prefix
)
) {
// Indexer may return `adminInfo`, in which case don't query again. If
// null, there is no admin to load. Otherwise. If not null, query
// chain.
if ('adminInfo' in dumpedState) {
const { adminInfo } = dumpedState as IndexerDumpState
if (adminInfo) {
const {
admin: adminAdmin,
info,
config: { name, image_url },
registeredSubDao = false,
} = adminInfo
const coreVersion = info && parseContractVersion(info.version)

if (coreVersion) {
parentDao = {
coreAddress: admin,
coreVersion,
name,
imageUrl: image_url || getFallbackImage(admin),
admin: adminAdmin ?? '',
registeredSubDao,
}
}
}
} else if (
get(
isContractSelector({
contractAddress: admin,
chainId,
names: [
// V1
'cw-core',
// V2
'cwd-core',
'dao-core',
],
})
)
) {
const adminAdmin = get(
DaoCoreV2Selectors.adminSelector({
contractAddress: admin,
chainId,
params: [],
})
)
const { version } = get(
DaoCoreV2Selectors.infoSelector({
contractAddress: admin,
chainId,
params: [],
})
).info
const adminVersion = parseContractVersion(version)

if (adminVersion) {
const {
name,
image_url,
}: CwCoreV1ConfigResponse | DaoCoreV2ConfigResponse = get(
// Both v1 and v2 have a config query.
DaoCoreV2Selectors.configSelector({
contractAddress: admin,
chainId,
params: [],
})
)

// Check if admin has registered the current DAO as a SubDAO.
const registeredSubDao =
adminVersion !== ContractVersion.V1
? get(
DaoCoreV2Selectors.listAllSubDaosSelector({
contractAddress: admin,
chainId,
})
).some(({ addr }) => addr === coreAddress)
: // V1 cannot have SubDAOs.
false

if (coreVersion) {
parentDao = {
coreAddress: admin,
coreVersion,
coreVersion: adminVersion,
name,
imageUrl: image_url || getFallbackImage(admin),
admin: adminAdmin ?? '',
Expand All @@ -107,68 +183,21 @@ export const daoCardInfoSelector = selectorFamily<
}
} else if (
get(
isContractSelector({
contractAddress: admin,
addressIsModuleSelector({
chainId,
names: [
// V1
'cw-core',
// V2
'cwd-core',
'dao-core',
],
address: admin,
})
)
) {
const adminAdmin = get(
DaoCoreV2Selectors.adminSelector({
contractAddress: admin,
chainId,
params: [],
})
)
const { version } = get(
DaoCoreV2Selectors.infoSelector({
contractAddress: admin,
chainId,
params: [],
})
).info
const adminVersion = parseContractVersion(version)

if (adminVersion) {
const {
name,
image_url,
}: CwCoreV1ConfigResponse | DaoCoreV2ConfigResponse = get(
// Both v1 and v2 have a config query.
DaoCoreV2Selectors.configSelector({
contractAddress: admin,
chainId,
params: [],
})
)

// Check if admin has registered the current DAO as a SubDAO.
const registeredSubDao =
adminVersion !== ContractVersion.V1
? get(
DaoCoreV2Selectors.listAllSubDaosSelector({
contractAddress: admin,
chainId,
})
).some(({ addr }) => addr === coreAddress)
: // V1 cannot have SubDAOs.
false

parentDao = {
coreAddress: admin,
coreVersion: adminVersion,
name,
imageUrl: image_url || getFallbackImage(admin),
admin: adminAdmin ?? '',
registeredSubDao,
}
// Chain module account.
const chainConfig = getSupportedChainConfig(chainId)
parentDao = chainConfig && {
coreAddress: chainConfig.name,
coreVersion: ContractVersion.Gov,
name: getDisplayNameForChainId(chainId),
imageUrl: getImageUrlForChainId(chainId),
admin: '',
registeredSubDao: false,
}
}
}
Expand Down
82 changes: 59 additions & 23 deletions packages/stateful/recoil/selectors/dao/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {
DaoCoreV2Selectors,
DaoVotingCw20StakedSelectors,
PolytoneProxySelectors,
addressIsModuleSelector,
contractInstantiateTimeSelector,
contractVersionSelector,
isContractSelector,
queryContractIndexerSelector,
} from '@dao-dao/state'
import {
Expand All @@ -19,6 +21,9 @@ import {
DaoVotingCw20StakedAdapterId,
POLYTONE_CONFIG_PER_CHAIN,
getChainForChainId,
getDisplayNameForChainId,
getImageUrlForChainId,
getSupportedChainConfig,
isValidContractAddress,
} from '@dao-dao/utils'

Expand Down Expand Up @@ -216,31 +221,62 @@ export const daoInfoSelector: (param: {

let parentDaoInfo
let parentSubDaos
if (
dumpState.admin &&
dumpState.admin !== coreAddress &&
isValidContractAddress(
dumpState.admin,
getChainForChainId(chainId).bech32_prefix
) &&
!ignoreAdmins?.includes(dumpState.admin)
) {
parentDaoInfo = get(
daoInfoSelector({
chainId,
coreAddress: dumpState.admin,
ignoreAdmins: [...(ignoreAdmins ?? []), coreAddress],
})
)

// Only v2 DAOs can have SubDAOs.
if (parentDaoInfo.coreVersion !== ContractVersion.V1) {
parentSubDaos = get(
DaoCoreV2Selectors.listAllSubDaosSelector({
if (dumpState.admin && dumpState.admin !== coreAddress) {
if (
isValidContractAddress(
dumpState.admin,
getChainForChainId(chainId).bech32_prefix
) &&
get(
isContractSelector({
contractAddress: dumpState.admin,
chainId,
names: [
// V1
'cw-core',
// V2
'cwd-core',
'dao-core',
],
})
).map(({ addr }) => addr)
) &&
!ignoreAdmins?.includes(dumpState.admin)
) {
parentDaoInfo = get(
daoInfoSelector({
chainId,
coreAddress: dumpState.admin,
ignoreAdmins: [...(ignoreAdmins ?? []), coreAddress],
})
)

// Only v2 DAOs can have SubDAOs.
if (parentDaoInfo.coreVersion !== ContractVersion.V1) {
parentSubDaos = get(
DaoCoreV2Selectors.listAllSubDaosSelector({
contractAddress: dumpState.admin,
chainId,
})
).map(({ addr }) => addr)
}
} else if (
get(
addressIsModuleSelector({
chainId,
address: dumpState.admin,
})
)
) {
// Chain module account.
const chainConfig = getSupportedChainConfig(chainId)
parentDaoInfo = chainConfig && {
coreAddress: chainConfig.name,
coreVersion: ContractVersion.Gov,
name: getDisplayNameForChainId(chainId),
imageUrl: getImageUrlForChainId(chainId),
admin: '',
registeredSubDao: false,
}
}
}

Expand All @@ -259,7 +295,7 @@ export const daoInfoSelector: (param: {
polytoneProxies,
parentDao: parentDaoInfo
? {
coreAddress: dumpState.admin,
coreAddress: parentDaoInfo.coreAddress,
coreVersion: parentDaoInfo.coreVersion,
name: parentDaoInfo.name,
imageUrl: parentDaoInfo.imageUrl || null,
Expand Down
Loading

2 comments on commit e02c228

@vercel
Copy link

@vercel vercel bot commented on e02c228 Sep 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on e02c228 Sep 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.