Skip to content

Commit

Permalink
Enable Approver action (#1815)
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahSaso authored Sep 20, 2024
1 parent 4818eef commit b7fef9a
Show file tree
Hide file tree
Showing 15 changed files with 520 additions and 16 deletions.
10 changes: 7 additions & 3 deletions packages/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@
"missingIbcChainAccounts_one": "An account needs to be created on the following chain so it can be used during this multi-hop IBC transaction: {{chains}}. In the event of a catastrophic failure, there is a small chance that a multi-hop IBC transaction will not be reversible, and tokens will end up on one of the intermediary chains. In this case, an account must exist on each intermediary to act as a failsafe. Either a cross-chain or ICA account works and will be automatically detected once created.",
"missingIbcChainAccounts_other": "Accounts need to be created on the following chains so they can be used during this multi-hop IBC transaction: {{chains}}. In the event of a catastrophic failure, there is a small chance that a multi-hop IBC transaction will not be reversible, and tokens will end up on one of the intermediary chains. In this case, an account must exist on each intermediary to act as a failsafe. Either a cross-chain or ICA account works and will be automatically detected once created.",
"missingNativeToken": "Missing native token.",
"multipleChoiceApprovalNotYetSupported": "Approval does not yet support multiple choice proposals. Disable the multiple choice proposal module before enabling an approver, or wait for multiple choice approval support.",
"mustBeAtLeastSixtySeconds": "Must be at least 60 seconds.",
"mustBeMemberToAddMember": "You must be a member of the DAO to propose adding a new member.",
"mustBeMemberToCreateCompensationCycle": "You must be a member of the DAO to create a compensation cycle.",
Expand Down Expand Up @@ -966,8 +967,8 @@
"approvalProposalExplanation_pending": "This proposal is waiting to be accepted by the approver so that it can open for voting.",
"approvalProposalExplanation_rejected": "This proposal was not allowed to open for voting because the approver rejected it.",
"approverEnabledNoMultipleChoice": "Approver is enabled, which is currently incompatible with multiple choice proposals.",
"approverExplanation_choosing": "DAOs shown below have this DAO ({{daoName}}) set as their approver. This action completes the setup process and automates the creation of approval proposals in {{daoName}} when the selected DAO below attempts to create a new proposal. Proposals created in the selected DAO before this setup is complete must be manually approved with the Execute Smart Contract action.",
"approverExplanation_chose": "The DAO shown below has this DAO ({{daoName}}) set as their approver. This action completes the setup process and automates the creation of approval proposals in {{daoName}} when the selected DAO below attempts to create a new proposal. Proposals created in the selected DAO before this setup is complete must be manually approved with the Execute Smart Contract action.",
"approverExplanation_choosing": "DAOs shown below have this DAO ({{daoName}}) set as their approver. This action completes the setup process and automates the creation of approval proposals in {{daoName}} when the selected DAO below attempts to create a new proposal.",
"approverExplanation_chose": "The DAO shown below has this DAO ({{daoName}}) set as their approver. This action completes the setup process and automates the creation of approval proposals in {{daoName}} when the selected DAO below attempts to create a new proposal.",
"approverProposalExplanation_closed": "This proposal is responsible for approving a proposal in another DAO. Since it was rejected and closed, the original proposal was not allowed to open for voting.",
"approverProposalExplanation_executed": "This proposal is responsible for approving a proposal in another DAO. Since it was passed and executed, the original proposal opened for voting.",
"approverProposalExplanation_execution_failed": "This proposal is responsible for approving a proposal in another DAO. An unexpected error occurred (execution failed). Something is wrong.",
Expand All @@ -983,7 +984,7 @@
"availableBalance": "Available balance",
"availableForWithdrawal": "available for withdrawal",
"availableHistoryLoaded": "All available history has been loaded.",
"becomeApproverDescription": "Assume responsibility for approving another DAO's proposals before they open for voting.",
"becomeApproverDescription": "Assume responsibility for approving another DAO's proposals before they open for voting. This can only be used after the other DAO sets this DAO as their approver.",
"becomeSubDaoActionDescription": "Provide the address of a DAO to request to become its SubDAO. The DAO will then need to accept your request to complete the ownership transfer and become your parent. Once the transfer is complete, only your new parent DAO can transfer ownership in the future. Keep in mind that your parent DAO will have full authority to execute anything it wants to on behalf of this DAO.",
"becomeSubDaoActionDescription_created": "The parent DAO needs to accept this request to complete the ownership transfer and become your parent. Once the transfer is complete, only your new parent DAO can transfer ownership in the future. Keep in mind that your parent DAO will have full authority to execute anything it wants to on behalf of this DAO.",
"becomeSubDaoDescription": "Request to become a SubDAO of a DAO.",
Expand Down Expand Up @@ -1089,6 +1090,8 @@
"emailVerificationResent": "Email verification resent.",
"emailVerified": "Email verified.",
"emptyInboxCaughtUp": "You're all caught up!",
"enableApproverDescription": "Require approval before proposals can open for voting.",
"enableApproverExplanation": "Enable an approver that must approve new proposals in this DAO before they open for voting. If the approver is a DAO, the approver DAO must pass and execute a proposal with the \"Become Approver\" action after this enable action is executed.",
"enableMultipleChoiceProposalsDescription": "Allow members to vote on many options in one proposal.",
"enableMultipleChoiceProposalsExplanation": "This action will enable the creation of multiple choice proposals, which allow voting on many options in one proposal. Each option can have a list of actions that execute if that option wins. It will be configured to match the current config of the single choice proposal module.",
"enableVetoerDaoDescription": "Display proposals from a DAO on the home page when they are vetoable.",
Expand Down Expand Up @@ -1766,6 +1769,7 @@
"documentation": "Documentation",
"editValidator": "Edit validator",
"email": "Email",
"enableApprover": "Enable Approver",
"enableMultipleChoiceProposals": "Enable Multiple Choice Proposals",
"enableRetroactiveCompensation": "Enable Retroactive Compensation",
"enableVestingPayments": "Enable Vesting Payments",
Expand Down
14 changes: 12 additions & 2 deletions packages/state/query/queries/proposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { PreProposeSubmissionPolicy } from '@dao-dao/types/contracts/DaoPrePropo
import { Config as NeutronCwdSubdaoTimelockSingleConfig } from '@dao-dao/types/contracts/NeutronCwdSubdaoTimelockSingle'
import {
ContractName,
DAO_PRE_PROPOSE_MULTIPLE_CONTRACT_NAMES,
DAO_PRE_PROPOSE_SINGLE_CONTRACT_NAMES,
getCosmWasmClientForChainId,
parseContractVersion,
} from '@dao-dao/utils'
Expand Down Expand Up @@ -45,7 +47,14 @@ export const fetchPreProposeModule = async (
const contractVersion = parseContractVersion(contractInfo.version)

let typedConfig: PreProposeModuleTypedConfig = {
type: PreProposeModuleType.Other,
// If normal DAO DAO pre-propose module, use normal. Otherwise, default to
// other.
type: [
...DAO_PRE_PROPOSE_SINGLE_CONTRACT_NAMES,
...DAO_PRE_PROPOSE_MULTIPLE_CONTRACT_NAMES,
].includes(contractInfo.contract)
? PreProposeModuleType.Normal
: PreProposeModuleType.Other,
}

// All pre-propose modules share the same config.
Expand All @@ -61,7 +70,8 @@ export const fetchPreProposeModule = async (
.catch(() => undefined)

switch (contractInfo.contract) {
case ContractName.PreProposeApprovalSingle: {
case ContractName.PreProposeApprovalSingle:
case ContractName.PreProposeApprovalMultiple: {
let approver: string | undefined
let preProposeApproverContract: string | null = null

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { ComponentType } from 'react'
import { useFormContext } from 'react-hook-form'
import { useTranslation } from 'react-i18next'

import {
InputErrorMessage,
InputLabel,
useActionOptions,
} from '@dao-dao/stateless'
import { AddressInputProps } from '@dao-dao/types'
import { ActionComponent, ActionContextType } from '@dao-dao/types/actions'
import { makeValidateAddress, validateRequired } from '@dao-dao/utils'

import {
MultipleChoiceProposalModule,
SecretMultipleChoiceProposalModule,
} from '../../../../clients'

export type EnableApproverData = {
approver: string
}

export type EnableApproverOptions = {
AddressInput: ComponentType<AddressInputProps<EnableApproverData>>
}

export const EnableApproverComponent: ActionComponent<
EnableApproverOptions
> = ({ isCreating, fieldNamePrefix, errors, options: { AddressInput } }) => {
const { t } = useTranslation()
const {
context,
chain: { bech32_prefix: bech32Prefix },
} = useActionOptions()
const { register } = useFormContext<EnableApproverData>()

return (
<>
{context.type === ActionContextType.Dao &&
context.dao.proposalModules.some(
(m) =>
m instanceof MultipleChoiceProposalModule ||
m instanceof SecretMultipleChoiceProposalModule
) && (
<p className="body-text text-text-interactive-error max-w-prose">
{t('error.multipleChoiceApprovalNotYetSupported')}
</p>
)}

<p className="body-text max-w-prose">
{t('info.enableApproverExplanation')}
</p>

<div className="flex flex-col gap-1 max-w-prose">
<InputLabel name={t('title.approver')} />
<AddressInput
disabled={!isCreating}
error={errors?.approver}
fieldName={(fieldNamePrefix + 'approver') as 'approver'}
register={register}
validation={[validateRequired, makeValidateAddress(bech32Prefix)]}
/>
<InputErrorMessage error={errors?.approver} />
</div>
</>
)
}
20 changes: 20 additions & 0 deletions packages/stateful/actions/core/actions/EnableApprover/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# EnableApprover

Enable an approver for an existing proposal module.

## Bulk import format

This is relevant when bulk importing actions, as described in [this
guide](https://github.com/DA0-DA0/dao-dao-ui/wiki/Bulk-importing-actions).

### Key

`enableApprover`

### Data format

```json
{
"approver": "<ADDRESS>"
}
```
Loading

0 comments on commit b7fef9a

Please sign in to comment.