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

Add Migaloo token factory migration action #1698

Merged
merged 5 commits into from
Mar 15, 2024
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
4 changes: 4 additions & 0 deletions packages/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@
"pick": "Mining pick",
"playPause": "Play pause",
"printer": "Printer",
"pufferfish": "Pufferfish",
"raisedHand": "Raised hand",
"recycle": "Recycle",
"robot": "Robot",
Expand Down Expand Up @@ -1058,7 +1059,9 @@
"mergeProfilesExplanation": "Select the profile you want to keep (the rest will be merged into it).",
"mergeProfilesTooltip": "Your wallet is attached to multiple profiles. Merge them to avoid confusion.",
"migrateFollowingDescription": "Followed DAOs require a migration to a new storage mechanism.",
"migrateMigalooV4TokenFactoryExplanation": "The token factory module on Migaloo has been migrated to a new version that is more actively maintained. Because this DAO created a new token before the migration, the DAO's token factory contract that interacts with the chain module must now be upgraded. This action upgrades the token factory contract to a version that supports the new token factory module.",
"migrateSmartContractActionDescription": "Migrate a CosmWasm contract to a new code ID.",
"migrateTokenFactoryModuleDescription": "Update the DAO to support the new token factory module.",
"minimumOutputRequiredDescription_dao": "Before the proposal is passed and executed, the swap price will fluctuate. If the price drops and no longer satisfies this minimum output required, the swap will not occur.",
"minimumOutputRequiredDescription_gov": "Before the proposal is passed and executed, the swap price will fluctuate. If the price drops and no longer satisfies this minimum output required, the swap will not occur.",
"minimumOutputRequiredDescription_wallet": "The exact swap price will fluctuate during the transaction, but the minimum output amount is guaranteed. If the price drops and no longer satisfies this minimum output required, the swap will not occur.",
Expand Down Expand Up @@ -1644,6 +1647,7 @@
"mergeProfiles": "Merge Profiles",
"migrateFollowing": "Migrate Followed DAOs",
"migrateSmartContract": "Migrate Smart Contract",
"migrateTokenFactoryModule": "Migrate Token Factory Module",
"minimumOutputRequired": "Minimum output required",
"mint": "Mint",
"mintNft": "Mint NFT",
Expand Down
27 changes: 16 additions & 11 deletions packages/state/recoil/selectors/contract.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CodeDetails } from '@cosmjs/cosmwasm-stargate'
import { CodeDetails, Contract } from '@cosmjs/cosmwasm-stargate'
import { fromUtf8, toUtf8 } from '@cosmjs/encoding'
import { selectorFamily } from 'recoil'

Expand Down Expand Up @@ -58,25 +58,30 @@ export const contractInstantiateTimeSelector = selectorFamily<
},
})

export const contractAdminSelector = selectorFamily<
string | undefined,
export const contractDetailsSelector = selectorFamily<
Contract,
WithChainId<{ contractAddress: string }>
>({
key: 'contractAdmin',
key: 'contractDetails',
get:
({ contractAddress, chainId }) =>
async ({ get }) => {
const client = get(cosmWasmClientForChainSelector(chainId))

try {
const contract = await client.getContract(contractAddress)
return contract.admin
} catch (_) {
return undefined
}
return await client.getContract(contractAddress)
},
})

export const contractAdminSelector = selectorFamily<
string | undefined,
WithChainId<{ contractAddress: string }>
>({
key: 'contractAdmin',
get:
(params) =>
({ get }) =>
get(contractDetailsSelector(params))?.admin,
})

export const codeDetailsSelector = selectorFamily<
CodeDetails,
WithChainId<{ codeId: number }>
Expand Down
2 changes: 1 addition & 1 deletion packages/stateful/creators/TokenBased/mutate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const mutate: DaoCreatorMutate<CreatorData> = (
active_threshold,
token_info: {
new: {
token_issuer_code_id: codeIds.CwTokenfactoryIssuer,
token_issuer_code_id: codeIds.CwTokenfactoryIssuerOsmosis,
subdenom: symbol.toLowerCase(),
initial_balances: microInitialBalances,
initial_dao_balance: microInitialTreasuryBalance,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'

import { makeReactHookFormDecorator } from '@dao-dao/storybook'

import {
MigrateMigalooV4TokenFactoryComponent,
MigrateMigalooV4TokenFactoryData,
} from './Component'

export default {
title:
'DAO DAO / packages / stateful / voting-module-adapter / adapters / DaoVotingTokenStaked / actions / MigrateMigalooV4TokenFactory',
component: MigrateMigalooV4TokenFactoryComponent,
decorators: [makeReactHookFormDecorator<MigrateMigalooV4TokenFactoryData>()],
} as ComponentMeta<typeof MigrateMigalooV4TokenFactoryComponent>

const Template: ComponentStory<typeof MigrateMigalooV4TokenFactoryComponent> = (
args
) => <MigrateMigalooV4TokenFactoryComponent {...args} />

export const Default = Template.bind({})
Default.args = {
fieldNamePrefix: '',
allActionsWithData: [],
index: 0,
data: {},
isCreating: true,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useTranslation } from 'react-i18next'

import { ActionComponent } from '@dao-dao/types'

export type MigrateMigalooV4TokenFactoryData = {}

export const MigrateMigalooV4TokenFactoryComponent: ActionComponent = () => {
const { t } = useTranslation()

return (
<p className="body-text max-w-prose">
{t('info.migrateMigalooV4TokenFactoryExplanation')}
</p>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# MigrateMigalooV4TokenFactory

Migrate `cw-tokenfactory-issuer` from the CosmWasm x/tokenfactory implementation
to Osmosis's x/tokenfactory. Migaloo is migrating tokenfactory modules, so this
is needed to help DAO's update to the latest contract.

## 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

`migrateMigalooV4TokenFactory`

### Data format

```json
{}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { useCallback } from 'react'

import {
DaoVotingTokenStakedSelectors,
contractDetailsSelector,
} from '@dao-dao/state/recoil'
import { PufferfishEmoji, useCachedLoadable } from '@dao-dao/stateless'
import { ChainId } from '@dao-dao/types'
import {
ActionChainContextType,
ActionKey,
ActionMaker,
UseDecodedCosmosMsg,
UseDefaults,
UseHideFromPicker,
UseTransformToCosmos,
} from '@dao-dao/types/actions'
import { makeWasmMessage, objectMatchesStructure } from '@dao-dao/utils'

import { useVotingModuleAdapterOptions } from '../../../../react/context'
import { useGovernanceTokenInfo } from '../../hooks'
import {
MigrateMigalooV4TokenFactoryComponent,
MigrateMigalooV4TokenFactoryData,
} from './Component'

const useDefaults: UseDefaults<MigrateMigalooV4TokenFactoryData> = () => ({})

export const makeMigrateMigalooV4TokenFactoryAction: ActionMaker<
MigrateMigalooV4TokenFactoryData
> = ({ t, chainContext }) => {
// Only Migaloo DAOs need to migrate.
if (
chainContext.chainId !== ChainId.MigalooMainnet ||
chainContext.type !== ActionChainContextType.Supported
) {
return null
}

const useTransformToCosmos: UseTransformToCosmos<
MigrateMigalooV4TokenFactoryData
> = () => {
const { tokenFactoryIssuerAddress } = useGovernanceTokenInfo()

return useCallback(
() =>
makeWasmMessage({
wasm: {
migrate: {
contract_addr: tokenFactoryIssuerAddress,
new_code_id:
chainContext.config.codeIds.CwTokenfactoryIssuerOsmosis,
msg: {},
},
},
}),
[tokenFactoryIssuerAddress]
)
}

const useDecodedCosmosMsg: UseDecodedCosmosMsg<
MigrateMigalooV4TokenFactoryData
> = (msg: Record<string, any>) => {
const { tokenFactoryIssuerAddress } = useGovernanceTokenInfo()

return objectMatchesStructure(msg, {
wasm: {
migrate: {
contract_addr: {},
new_code_id: {},
msg: {},
},
},
}) && msg.wasm.migrate.contract_addr === tokenFactoryIssuerAddress
? {
match: true,
data: {},
}
: {
match: false,
}
}

// Only show in picker if using cw-tokenfactory-issuer contract and it's on the
// old version of the contract.
const useHideFromPicker: UseHideFromPicker = () => {
const { chainId, votingModuleAddress } = useVotingModuleAdapterOptions()

const tfIssuer = useCachedLoadable(
DaoVotingTokenStakedSelectors.validatedTokenfactoryIssuerContractSelector(
{
contractAddress: votingModuleAddress,
chainId,
}
)
)
const tfIssuerContract = useCachedLoadable(
tfIssuer.state === 'hasValue' && tfIssuer.contents
? contractDetailsSelector({
contractAddress: tfIssuer.contents,
chainId,
})
: undefined
)

return (
!chainContext.config.codeIds.CwTokenfactoryIssuerCosmWasm ||
tfIssuerContract.state !== 'hasValue' ||
tfIssuerContract.contents.codeId !==
chainContext.config.codeIds.CwTokenfactoryIssuerCosmWasm
)
}

return {
key: ActionKey.MigrateMigalooV4TokenFactory,
Icon: PufferfishEmoji,
label: t('title.migrateTokenFactoryModule'),
description: t('info.migrateTokenFactoryModuleDescription'),
Component: MigrateMigalooV4TokenFactoryComponent,
useDefaults,
useTransformToCosmos,
useDecodedCosmosMsg,
useHideFromPicker,
// Show at the top.
order: 1000,
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { useCallback } from 'react'

import { DaoVotingTokenStakedSelectors } from '@dao-dao/state/recoil'
import {
DaoVotingTokenStakedSelectors,
contractDetailsSelector,
} from '@dao-dao/state/recoil'
import { HerbEmoji, useCachedLoadable } from '@dao-dao/stateless'
import { ChainId } from '@dao-dao/types'
import {
ActionChainContextType,
ActionComponent,
ActionKey,
ActionMaker,
Expand All @@ -18,6 +23,7 @@ import {
objectMatchesStructure,
} from '@dao-dao/utils'

import { useActionOptions } from '../../../../../actions'
import { AddressInput } from '../../../../../components/AddressInput'
import { useVotingModuleAdapterOptions } from '../../../../react/context'
import { useGovernanceTokenInfo } from '../../hooks'
Expand Down Expand Up @@ -108,15 +114,33 @@ const Component: ActionComponent = (props) => {
// Only show in picker if using cw-tokenfactory-issuer contract.
const useHideFromPicker: UseHideFromPicker = () => {
const { chainId, votingModuleAddress } = useVotingModuleAdapterOptions()
const { chainContext } = useActionOptions()

const tfIssuer = useCachedLoadable(
DaoVotingTokenStakedSelectors.validatedTokenfactoryIssuerContractSelector({
contractAddress: votingModuleAddress,
chainId,
})
)
const tfIssuerContract = useCachedLoadable(
tfIssuer.state === 'hasValue' && tfIssuer.contents
? contractDetailsSelector({
contractAddress: tfIssuer.contents,
chainId,
})
: undefined
)

return tfIssuer.state !== 'hasValue' || !tfIssuer.contents
return (
tfIssuer.state !== 'hasValue' ||
!tfIssuer.contents ||
// Disallow minting on Miagloo if cw-tokenfactory-issuer is on old version.
(chainContext.chainId === ChainId.MigalooMainnet &&
chainContext.type === ActionChainContextType.Supported &&
(tfIssuerContract.state !== 'hasValue' ||
tfIssuerContract.contents.codeId ===
chainContext.config.codeIds.CwTokenfactoryIssuerCosmWasm))
)
}

export const makeMintAction: ActionMaker<MintData> = ({ t, address }) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './MigrateMigalooV4TokenFactory'
export * from './Mint'
export * from './UpdateMinterAllowance'
export * from './UpdateStakingConfig'
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '@dao-dao/utils'

import {
makeMigrateMigalooV4TokenFactoryAction,
makeMintAction,
makeUpdateMinterAllowanceAction,
makeUpdateStakingConfigAction,
Expand Down Expand Up @@ -51,13 +52,19 @@ export const DaoVotingTokenStakedAdapter: VotingModuleAdapter = {
// Functions
fields: {
actionCategoryMakers: [
() => ({
// Add to Commonly Used category.
key: ActionCategoryKey.CommonlyUsed,
actionMakers: [makeMigrateMigalooV4TokenFactoryAction],
}),
() => ({
// Add to DAO Governance category.
key: ActionCategoryKey.DaoGovernance,
actionMakers: [
makeMintAction,
makeUpdateMinterAllowanceAction,
makeUpdateStakingConfigAction,
makeMigrateMigalooV4TokenFactoryAction,
],
}),
],
Expand Down
Loading
Loading