diff --git a/packages/i18n/locales/en/translation.json b/packages/i18n/locales/en/translation.json index 5f3fc61e3..7c72d117c 100644 --- a/packages/i18n/locales/en/translation.json +++ b/packages/i18n/locales/en/translation.json @@ -901,6 +901,7 @@ "info": { "abstainVote": "Abstain", "acceptSubDaoActionDescription": "Accept a pending SubDAO's ownership transfer request. Be sure that the SubDAO-to-be has already requested to join your DAO through the \"Become SubDAO\" action.", + "acceptSubDaoActionOtherActionsAdded": "Other actions that are required to register a new SubDAO have been added to the proposal automatically.", "acceptSubDaoDescription": "Accept a DAO's request to become a SubDAO.", "acknowledgeServiceFee": "We acknowledge that {{fee}} will be charged from the treasury for registration to the rebalancer.", "acknowledgeServiceFee_none": "We acknowledge that there is no fee to register for the rebalancer.", @@ -952,6 +953,7 @@ "availableBalance": "Available balance", "availableHistoryLoaded": "All available history has been loaded.", "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.", "betterNonPfmIbcPathAvailable": "A better path exists that unwinds the IBC token properly, but it requires hops that cannot be performed in a single proposal due to the configuration of one or more of the chains involved. You may safely use the direct path above, though it likely results in an undesirable IBC token on the final chain that will eventually need to be unwound. If you wish to unwind it manually, follow the path below by creating an individual proposal for the first hop, then a second proposal once the first one is passed and executed, and so on.", "betterPfmIbcPathAvailable_one": "A better path exists that unwinds the IBC token properly, but it requires you to have an account on {{chains}}. An account must exist on each intermediary chain in a multi-hop transaction to act as a failsafe in the event of catastrophic failure (unlikely). Either a cross-chain or ICA account works and will be automatically detected once created. You may safely use the direct path above, though it likely results in an undesirable IBC token on the final chain that will eventually need to be unwound.", diff --git a/packages/stateful/actions/core/smart_contracting/UpdateAdmin/index.tsx b/packages/stateful/actions/core/smart_contracting/UpdateAdmin/index.tsx index d396a9096..dd84bb62d 100644 --- a/packages/stateful/actions/core/smart_contracting/UpdateAdmin/index.tsx +++ b/packages/stateful/actions/core/smart_contracting/UpdateAdmin/index.tsx @@ -33,7 +33,7 @@ import { import { useActionOptions } from '../../../react' import { UpdateAdminComponent as StatelessUpdateAdminComponent } from './Component' -interface UpdateAdminData { +export type UpdateAdminData = { chainId: string contract: string newAdmin: string diff --git a/packages/stateful/actions/core/subdaos/AcceptSubDao/Component.tsx b/packages/stateful/actions/core/subdaos/AcceptSubDao/Component.tsx index a25c543b3..00847c900 100644 --- a/packages/stateful/actions/core/subdaos/AcceptSubDao/Component.tsx +++ b/packages/stateful/actions/core/subdaos/AcceptSubDao/Component.tsx @@ -1,13 +1,20 @@ -import { ComponentType } from 'react' +import { ComponentType, useEffect, useState } from 'react' import { useFormContext } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { InputErrorMessage, InputLabel } from '@dao-dao/stateless' import { AddressInputProps } from '@dao-dao/types' -import { ActionComponent } from '@dao-dao/types/actions' -import { makeValidateAddress, validateRequired } from '@dao-dao/utils' +import { ActionComponent, ActionKey } from '@dao-dao/types/actions' +import { + isValidBech32Address, + makeValidateAddress, + validateRequired, +} from '@dao-dao/utils' import { useActionOptions } from '../../../react' +import { DaoAdminExecData } from '../../dao_governance/DaoAdminExec/Component' +import { UpdateAdminData } from '../../smart_contracting/UpdateAdmin' +import { ManageSubDaosData } from '../ManageSubDaos/Component' export type AcceptSubDaoData = { address: string @@ -20,20 +27,135 @@ type AcceptSubDaoDataOptions = { export const AcceptSubDaoComponent: ActionComponent< AcceptSubDaoDataOptions, AcceptSubDaoData -> = ({ fieldNamePrefix, errors, isCreating, options: { AddressInput } }) => { +> = ({ + fieldNamePrefix, + errors, + isCreating, + allActionsWithData, + index, + addAction, + options: { AddressInput }, +}) => { const { t } = useTranslation() const { - chain: { bech32_prefix: bech32Prefix }, + address: currentAddress, + chain: { chain_id: chainId, bech32_prefix: bech32Prefix }, } = useActionOptions() - const { register } = useFormContext() + const { watch, register, setValue, getValues } = + useFormContext() const addressFieldName = (fieldNamePrefix + 'address') as 'address' + const address = watch(addressFieldName) + const isValid = !!address && isValidBech32Address(address, bech32Prefix) + const [otherActionsAdded, setOtherActionsAdded] = useState(false) + useEffect(() => { + if (!isCreating || !isValid) { + return + } + + const existingUpdateAdminIndex = allActionsWithData.findIndex( + (a, i) => + i > index && + a.actionKey === ActionKey.DaoAdminExec && + (a.data as DaoAdminExecData)?._actionData?.length === 1 && + (a.data as DaoAdminExecData)._actionData![0].actionKey === + ActionKey.UpdateAdmin && + (a.data as DaoAdminExecData)._actionData![0].data.newAdmin === + currentAddress + ) + const existingManageSubDaosIndex = allActionsWithData.findIndex( + (a, i) => i > index && a.actionKey === ActionKey.ManageSubDaos + ) + + if (existingUpdateAdminIndex === -1) { + addAction( + { + actionKey: ActionKey.DaoAdminExec, + data: { + coreAddress: address, + _actionData: [ + { + actionKey: ActionKey.UpdateAdmin, + data: { + chainId, + contract: address, + newAdmin: currentAddress, + } as UpdateAdminData, + }, + ], + } as DaoAdminExecData, + }, + // After current action. + index + 1 + ) + } else { + // Path to the address field on the update admin sub-action of the DAO + // admin exec action. + const existingAddressFieldName = fieldNamePrefix.replace( + new RegExp(`${index}\\.data.$`), + `${existingUpdateAdminIndex}.data._actionData.0.data.contract` + ) + + // If the address isn't correct, update the existing one. + if (getValues(existingAddressFieldName as any) !== address) { + setValue(existingAddressFieldName as any, address) + } + } + + if (existingManageSubDaosIndex === -1) { + addAction( + { + actionKey: ActionKey.ManageSubDaos, + data: { + toAdd: [ + { + addr: address, + }, + ], + toRemove: [], + } as ManageSubDaosData, + }, + // After DAO admin exec / update admin action. + index + 2 + ) + } else { + // Path to the address field on the manage subDAOs action. + const existingAddressFieldName = fieldNamePrefix.replace( + new RegExp(`${index}\\.data.$`), + `${existingManageSubDaosIndex}.data.toAdd.0.addr` + ) + + // If the address isn't correct, update the existing one. + if (getValues(existingAddressFieldName as any) !== address) { + setValue(existingAddressFieldName as any, address) + } + } + + setOtherActionsAdded(true) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ + isCreating, + isValid, + address, + index, + addAction, + currentAddress, + chainId, + fieldNamePrefix, + getValues, + setValue, + ]) + return ( <>
-

{t('info.acceptSubDaoActionDescription')}

+ {isCreating && ( +

+ {t('info.acceptSubDaoActionDescription')} +

+ )}
@@ -47,6 +169,12 @@ export const AcceptSubDaoComponent: ActionComponent< />
+ + {otherActionsAdded && ( +

+ {t('info.acceptSubDaoActionOtherActionsAdded')} +

+ )}
) diff --git a/packages/stateful/actions/core/subdaos/BecomeSubDao/Component.tsx b/packages/stateful/actions/core/subdaos/BecomeSubDao/Component.tsx index 8c5a09f29..7178c132a 100644 --- a/packages/stateful/actions/core/subdaos/BecomeSubDao/Component.tsx +++ b/packages/stateful/actions/core/subdaos/BecomeSubDao/Component.tsx @@ -33,7 +33,11 @@ export const BecomeSubDaoComponent: ActionComponent< return ( <>
-

{t('info.becomeSubDaoActionDescription')}

+

+ {t('info.becomeSubDaoActionDescription', { + context: !isCreating ? 'created' : undefined, + })} +

diff --git a/packages/stateful/actions/core/subdaos/BecomeSubDao/index.tsx b/packages/stateful/actions/core/subdaos/BecomeSubDao/index.tsx index 47629f383..238aa5166 100644 --- a/packages/stateful/actions/core/subdaos/BecomeSubDao/index.tsx +++ b/packages/stateful/actions/core/subdaos/BecomeSubDao/index.tsx @@ -23,7 +23,7 @@ const useDecodedCosmosMsg: UseDecodedCosmosMsg = ( return { match: true, data: { - admin: msg.wasm.execute.nominate_admin.admin, + admin: msg.wasm.execute.msg.nominate_admin.admin, }, } } catch { diff --git a/packages/stateful/actions/core/subdaos/ManageSubDaos/Component.tsx b/packages/stateful/actions/core/subdaos/ManageSubDaos/Component.tsx index 24fc7c071..b0d45253e 100644 --- a/packages/stateful/actions/core/subdaos/ManageSubDaos/Component.tsx +++ b/packages/stateful/actions/core/subdaos/ManageSubDaos/Component.tsx @@ -20,7 +20,7 @@ import { makeValidateAddress, validateRequired } from '@dao-dao/utils' import { useActionOptions } from '../../../react' -export interface ManageSubDaosData { +export type ManageSubDaosData = { toAdd: SubDao[] toRemove: { address: string }[] }