Skip to content

Commit

Permalink
detect vesting contracts owned by a DAO even if they're from a differ…
Browse files Browse the repository at this point in the history
…ent factory
  • Loading branch information
NoahSaso committed Sep 25, 2024
1 parent 2db62ba commit 0f43901
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 1 deletion.
90 changes: 90 additions & 0 deletions packages/state/query/queries/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { fromUtf8, toUtf8 } from '@cosmjs/encoding'
import { QueryClient, queryOptions, skipToken } from '@tanstack/react-query'

import { InfoResponse } from '@dao-dao/types'
import {
ArrayOfVestingContract,
VestingContract,
} from '@dao-dao/types/contracts/CwPayrollFactory'
import { CodeInfoResponse } from '@dao-dao/types/protobuf/codegen/cosmwasm/wasm/v1/query'
import { AccessType } from '@dao-dao/types/protobuf/codegen/cosmwasm/wasm/v1/types'
import {
Expand All @@ -19,6 +23,7 @@ import {
} from '@dao-dao/utils'

import { chainQueries } from './chain'
import { cwVestingQueries } from './contracts'
import { indexerQueries } from './indexer'

/**
Expand Down Expand Up @@ -311,6 +316,54 @@ export const generateInstantiate2Address = async (
)
}

/**
* List all vesting contracts owned by a given account.
*/
export const listVestingContractsOwnedByAccount = async (
queryClient: QueryClient,
{
chainId,
address,
}: {
chainId: string
address: string
}
): Promise<{
chainId: string
contracts: ArrayOfVestingContract
}> => {
const vestingContracts = await queryClient.fetchQuery(
contractQueries.listContractsOwnedByAccount(queryClient, {
chainId,
address,
key: 'cw-vesting',
})
)

const contracts = await Promise.all(
vestingContracts.map(
async (contract): Promise<VestingContract> => ({
contract,
recipient: (
await queryClient.fetchQuery(
cwVestingQueries.info(queryClient, {
chainId,
contractAddress: contract,
})
)
).recipient,
// Ignore.
instantiator: '',
})
)
)

return {
chainId,
contracts,
}
}

export const contractQueries = {
/**
* Fetch contract info stored in state, which contains its name and version.
Expand Down Expand Up @@ -431,4 +484,41 @@ export const contractQueries = {
queryKey: ['contract', 'instantiate2Address', options],
queryFn: () => generateInstantiate2Address(queryClient, options),
}),
/**
* List all contracts owned by a given account.
*/
listContractsOwnedByAccount: (
queryClient: QueryClient,
{
chainId,
address,
key,
}: {
chainId: string
address: string
/**
* Optionally filter by an indexer code ID key.
*/
key?: string
}
) =>
indexerQueries.queryAccount<string[]>(queryClient, {
chainId,
address,
formula: 'contract/ownedBy',
args: {
key,
},
}),
/**
* List all vesting contracts owned by a given account.
*/
listVestingContractsOwnedByAccount: (
queryClient: QueryClient,
options: Parameters<typeof listVestingContractsOwnedByAccount>[1]
) =>
queryOptions({
queryKey: ['contract', 'listVestingContractsOwnedByAccount', options],
queryFn: () => listVestingContractsOwnedByAccount(queryClient, options),
}),
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { useQueries, useQueryClient } from '@tanstack/react-query'
import uniqBy from 'lodash.uniqby'

import {
contractQueries,
cwPayrollFactoryExtraQueries,
cwVestingExtraQueries,
} from '@dao-dao/state/query'
Expand Down Expand Up @@ -31,7 +33,7 @@ import { TabRenderer as StatelessTabRenderer } from './TabRenderer'
export const TabRenderer = ({
variables: { factories, factory, oldFactories },
}: WidgetRendererProps<VestingPaymentsWidgetData>) => {
const { chainId: defaultChainId, coreAddress } = useDaoInfoContext()
const { chainId: defaultChainId, coreAddress, accounts } = useDaoInfoContext()
const { getDaoProposalPath } = useDaoNavHelpers()
const { isMember = false } = useMembership()

Expand Down Expand Up @@ -67,11 +69,22 @@ export const TabRenderer = ({
address,
})
),

// Contracts owned by any of this DAO's accounts. This detects contracts
// whose ownership was transferred to this DAO but that are still part of
// a different factory.
...accounts.map(({ chainId, address }) =>
contractQueries.listVestingContractsOwnedByAccount(queryClient, {
chainId,
address,
})
),
],
combine: makeCombineQueryResultsIntoLoadingDataWithError({
firstLoad: 'one',
}),
})

// Fetch infos individually so they refresh when data is updated elsewhere.
const vestingInfosLoading = useQueries({
queries:
Expand All @@ -87,6 +100,13 @@ export const TabRenderer = ({
),
combine: makeCombineQueryResultsIntoLoadingDataWithError({
firstLoad: 'one',
// De-dupe since the ownership queries will overlap with the factory list
// queries.
transform: (infos) =>
uniqBy(
infos,
(info) => info.chainId + ':' + info.vestingContractAddress
),
}),
})

Expand Down

0 comments on commit 0f43901

Please sign in to comment.