Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect when parent DAO is chain module #1368

Merged
merged 1 commit into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading