Skip to content

Commit

Permalink
Merge pull request #14 from ethereum-optimism/11-20-feat_hook_up_depl…
Browse files Browse the repository at this point in the history
…oy_wizard

feat: hook up deploy wizard
  • Loading branch information
jakim929 authored Nov 21, 2024
2 parents 46d229b + 9c49195 commit 20d4ac3
Show file tree
Hide file tree
Showing 30 changed files with 623 additions and 684 deletions.
11 changes: 1 addition & 10 deletions packages/cli/src/actions/deployCreateXCreate2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,6 @@ export const zodDeployCreateXCreate2Params = z.object({
)
.min(4)
.optional(),
initArgs: z
.string()
.describe(
option({
description: 'Arguments to initialize the ERC20 contract',
alias: 'iargs',
}),
)
.min(4)
.optional(),
salt: z.string().describe(
option({
description: 'Salt',
Expand Down Expand Up @@ -95,6 +85,7 @@ const createDeployContext = async ({
constructorArgs,
}: DeployCreateXCreate2Params) => {
const chainByIdentifier = await queryMappingChainByIdentifier();

const artifact = await queryForgeArtifact(forgeArtifactPath);

const chainIdentifiers = chains.map(chain => `${network}/${chain}`);
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/bridge-wizard/BridgeWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {EnterAmount} from '@/bridge-wizard/EnterAmount';
import {EnterPrivateKey} from '@/bridge-wizard/EnterPrivateKey';
import {SelectChains} from '@/bridge-wizard/SelectChains';
import {SelectNetwork} from '@/bridge-wizard/SelectNetwork';
import DeployCreate2Command from '@/commands/deploy/create2';
import {Box, Text} from 'ink';

type StepStatus = 'done' | 'current' | 'upcoming';
Expand Down
5 changes: 1 addition & 4 deletions packages/cli/src/bridge-wizard/bridgeWizardStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import {defineWizard, InferStepId} from '@/wizard-builder/defineWizard';
import {z} from 'zod';
import {formatEther} from 'viem';
import {Address as ZodAddress} from 'abitype/zod';
import {
createWizardStore,
WizardPossibleStates,
} from '@/wizard-builder/createWizardStore';
import {createWizardStore} from '@/wizard-builder/createWizardStore';

const bridgeWizard = defineWizard()
.addStep({
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/deploy/create2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const useDeterministicAddress = (params: DeployCreateXCreate2Params) => {
});
};

const DeployErc20Command = ({
const DeployCreate2Command = ({
options,
}: {
options: DeployCreateXCreate2Params;
Expand Down Expand Up @@ -171,5 +171,5 @@ const DeployErc20Command = ({
);
};

export default DeployErc20Command;
export default DeployCreate2Command;
export const options = zodDeployCreateXCreate2Params;
4 changes: 2 additions & 2 deletions packages/cli/src/commands/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Wizard} from '@/wizard/Wizard';
import {DeployCreate2Wizard} from '@/deploy-create2-wizard/DeployCreate2Wizard';

const Index = () => {
return <Wizard onSubmit={form => console.log(form)} />;
return <DeployCreate2Wizard />;
};

export default Index;
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,9 @@ export const AbiItemInput = <T extends AbiParameter>({
};

return (
<Box flexDirection="column" gap={1}>
<Box flexDirection="column">
<Text color="red">{error ? `❌ ${error}` : ' '}</Text>

<TextInput
key={`${attemptCount}`}
onSubmit={handleSubmit}
placeholder="Type value and press Enter"
/>
<TextInput key={`${attemptCount}`} onSubmit={handleSubmit} />
</Box>
);
};
Expand All @@ -92,14 +87,14 @@ export const AbiItemForm = <T extends AbiConstructor | AbiFunction>({
const [currentIndex, setCurrentIndex] = useState(0);

return (
<Box flexDirection="column" padding={1}>
<Box flexDirection="column">
<Box marginBottom={1}>
<Text bold color="blue">
📝 Enter function arguments
</Text>
</Box>

<Box flexDirection="column" marginBottom={1}>
<Box flexDirection="column">
{inputs.map((input, index) => (
<Box key={index}>
<Text>
Expand All @@ -109,15 +104,15 @@ export const AbiItemForm = <T extends AbiConstructor | AbiFunction>({
{values[index] ? (
<Text color="cyan"> = {values[index]}</Text>
) : (
<Text dimColor> (not set)</Text>
<Text dimColor> </Text>
)}
{currentIndex > index && <Text color="green"></Text>}
</Text>
</Box>
))}
</Box>

<Box marginBottom={1}>
<Box marginTop={1}>
<Text dimColor>Enter value for </Text>
<Text bold color="yellow">
{inputs[currentIndex]?.name || 'unnamed'}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {useDeployCreate2WizardStore} from '@/deploy-create2-wizard/deployCreate2WizardStore';
import {getConstructorAbi} from '@/utils/abi';
import {Box} from 'ink';
import {AbiItemForm} from '@/deploy-create2-wizard/AbiItemForm';
import {getArtifactPathForContract} from '@/forge/foundryProject';
import {useForgeArtifact} from '@/queries/forgeArtifact';
import {Spinner} from '@inkjs/ui';

export const ConfigureConstructorArguments = () => {
const {wizardState, submitConfigureConstructorArguments} =
useDeployCreate2WizardStore();

if (wizardState.stepId !== 'configure-constructor-arguments') {
throw new Error('Invalid state');
}

const path = getArtifactPathForContract(
wizardState.foundryProjectPath,
wizardState.selectedContract,
);

const {data: artifact, isLoading} = useForgeArtifact(path);

if (isLoading || !artifact) {
return (
<Box flexDirection="column">
<Spinner label="Loading artifact..." />
</Box>
);
}

const constructorAbi = getConstructorAbi(artifact.abi);

if (!constructorAbi) {
throw new Error('No constructor ABI found');
}

return (
<Box flexDirection="column">
<AbiItemForm
abiItem={constructorAbi}
onSubmit={result => {
// TODO fix type
submitConfigureConstructorArguments({constructorArgs: result});
}}
/>
</Box>
);
};
22 changes: 22 additions & 0 deletions packages/cli/src/deploy-create2-wizard/ConfigureSalt.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {useDeployCreate2WizardStore} from '@/deploy-create2-wizard/deployCreate2WizardStore';
import {Box, Text} from 'ink';
import {TextInput} from '@inkjs/ui';
export const ConfigureSalt = () => {
const {wizardState, submitConfigureSalt} = useDeployCreate2WizardStore();

if (wizardState.stepId !== 'configure-salt') {
throw new Error('Invalid state');
}

return (
<Box flexDirection="column">
<Box>
<Text>Enter a salt value (press Enter to confirm):</Text>
</Box>
<TextInput
onSubmit={salt => submitConfigureSalt({salt})}
defaultValue={'ethers phoenix'}
/>
</Box>
);
};
140 changes: 140 additions & 0 deletions packages/cli/src/deploy-create2-wizard/DeployCreate2Wizard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import {
deployCreate2WizardIndexByStepId,
DeployCreate2WizardStepId,
useDeployCreate2WizardStore,
} from '@/deploy-create2-wizard/deployCreate2WizardStore';
import {Box, Text} from 'ink';
import {EnterFoundryProjectPath} from '@/deploy-create2-wizard/EnterFoundryProjectPath';
import {SelectContract} from '@/deploy-create2-wizard/SelectContract';
import {ConfigureConstructorArguments} from '@/deploy-create2-wizard/ConfigureConstructorArguments';
import {ConfigureSalt} from '@/deploy-create2-wizard/ConfigureSalt';
import {SelectNetwork} from '@/deploy-create2-wizard/SelectNetwork';
import {SelectChains} from '@/deploy-create2-wizard/SelectChains';
import {EnterPrivateKey} from '@/deploy-create2-wizard/EnterPrivateKey';
import DeployCreate2Command from '@/commands/deploy/create2';
import {getArtifactPathForContract} from '@/forge/foundryProject';

type StepStatus = 'done' | 'current' | 'upcoming';

type StepProgress = {
status: StepStatus;
title: string;
summary?: string;
};

const useStepProgress = ({
stepId,
}: {
stepId: DeployCreate2WizardStepId;
}): StepProgress => {
const {steps, wizardState} = useDeployCreate2WizardStore();

const currentIndex = deployCreate2WizardIndexByStepId[wizardState.stepId];
const stepIndex = deployCreate2WizardIndexByStepId[stepId];

const step = steps[stepIndex]!;

if (stepIndex < currentIndex) {
return {
status: 'done' as const,
title: step.title,
summary: step.getSummary
? step.getSummary(wizardState as unknown as any)
: undefined,
};
}

if (stepIndex === currentIndex) {
return {
status: 'current' as const,
title: step.title,
};
}

return {
status: 'upcoming' as const,
title: step.title,
};
};

const WizardProgressForStep = ({
stepId,
}: {
stepId: DeployCreate2WizardStepId;
}) => {
const {status, title, summary} = useStepProgress({stepId});

return (
<Box gap={1} paddingX={1}>
<Text
color={
status === 'done' ? 'green' : status === 'current' ? 'blue' : 'gray'
}
>
{status === 'done' ? '✓' : status === 'current' ? '>' : '○'}
</Text>
<Text color={status === 'current' ? 'blue' : 'white'}> {title}</Text>
{status === 'done' && summary && <Text color="yellow">{summary}</Text>}
</Box>
);
};

const WizardProgress = () => {
const {steps, wizardState} = useDeployCreate2WizardStore();
if (wizardState.stepId === 'completed') {
return (
<Box>
<Text>Completed</Text>
</Box>
);
}
return (
<Box flexDirection="column">
{steps.map(({id}) => {
return <WizardProgressForStep stepId={id} key={id} />;
})}
</Box>
);
};

export const DeployCreate2Wizard = () => {
const {wizardState} = useDeployCreate2WizardStore();

const stepId = wizardState.stepId;

if (stepId === 'completed') {
return (
<DeployCreate2Command
options={{
chains: wizardState.chainNames,
privateKey: wizardState.privateKey,
salt: wizardState.salt,
forgeArtifactPath: getArtifactPathForContract(
wizardState.foundryProjectPath,
wizardState.selectedContract,
),
constructorArgs: wizardState.constructorArgs.join(','),
network: wizardState.network,
}}
/>
);
}

return (
<Box flexDirection="column" gap={1}>
<Text bold color="blue">
🚀 Deploy Create2 Wizard
</Text>
<WizardProgress />
{stepId === 'enter-foundry-project-path' && <EnterFoundryProjectPath />}
{stepId === 'select-contract' && <SelectContract />}
{stepId === 'configure-constructor-arguments' && (
<ConfigureConstructorArguments />
)}
{stepId === 'configure-salt' && <ConfigureSalt />}
{stepId === 'select-network' && <SelectNetwork />}
{stepId === 'select-chains' && <SelectChains />}
{stepId === 'enter-private-key' && <EnterPrivateKey />}
</Box>
);
};
27 changes: 27 additions & 0 deletions packages/cli/src/deploy-create2-wizard/EnterFoundryProjectPath.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {useDeployCreate2WizardStore} from '@/deploy-create2-wizard/deployCreate2WizardStore';
import {Box, Text} from 'ink';
import {TextInput} from '@inkjs/ui';

export const EnterFoundryProjectPath = () => {
const {wizardState, submitEnterFoundryProjectPath} =
useDeployCreate2WizardStore();

if (wizardState.stepId !== 'enter-foundry-project-path') {
throw new Error('Invalid state');
}

return (
<Box flexDirection="column">
<Box>
<Text>Enter the path to your foundry project:</Text>
</Box>
<TextInput
onSubmit={foundryProjectPath =>
submitEnterFoundryProjectPath({
foundryProjectPath: foundryProjectPath.trim(),
})
}
/>
</Box>
);
};
Loading

0 comments on commit 20d4ac3

Please sign in to comment.