From b84125fd38ef3ae55ffb45bd1c559e16cac5f23e Mon Sep 17 00:00:00 2001 From: Marcos Date: Tue, 10 Dec 2024 09:26:51 -0300 Subject: [PATCH 1/5] add view deployment button + improve messages --- .../wizard/components/ApprovalProcess.svelte | 8 +++----- src/lib/wizard/components/shared/Button.svelte | 17 ++++++++++++++--- src/lib/wizard/components/shared/Message.svelte | 11 +++++++---- src/routes/wizard.svelte | 17 +++++++++++++++-- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/lib/wizard/components/ApprovalProcess.svelte b/src/lib/wizard/components/ApprovalProcess.svelte index 5450f97..1319a68 100644 --- a/src/lib/wizard/components/ApprovalProcess.svelte +++ b/src/lib/wizard/components/ApprovalProcess.svelte @@ -7,6 +7,7 @@ import type { Relayer } from "$lib/models/relayer"; import { getNetworkLiteral } from "$lib/models/network"; import Input from "./shared/Input.svelte"; + import Message from "./shared/Message.svelte"; let address = $state(globalState.form.approvalProcessToCreate?.via || ""); @@ -167,11 +168,8 @@ {:else if approvalProcessType === "Relayer"} {#if disableRelayers} -
- -

- API Key not allowed to manage Relayers -

+
+
{:else} type Props = { - loading: boolean; + loading?: boolean; onClick: () => void; label: string; disabled?: boolean; + type?: 'primary' | 'secondary'; }; - const { loading, onClick, label, disabled }: Props = $props(); + const { loading, onClick, label, disabled, type }: Props = $props(); + + let buttonClass = $derived.by(() => { + if (loading) { + return 'bg-gray-400 text-white text-sm rounded-md p-2 mt-2'; + } + if (type === 'secondary') { + return 'bg-transparent text-gray-800 text-sm border border-gray-800 rounded-md p-2 mt-2'; + } + return 'bg-blue-600 text-white text-sm rounded-md p-2 mt-2'; + }); -
-{/if} \ No newline at end of file +{:else if type === 'warn'} +
+ +
{message}
+
+{/if} diff --git a/src/routes/wizard.svelte b/src/routes/wizard.svelte index 02794fe..af51ffe 100644 --- a/src/routes/wizard.svelte +++ b/src/routes/wizard.svelte @@ -11,7 +11,7 @@ import { buildCompilerInput, type ContractSources } from "$lib/models/solc"; import Message from "$lib/wizard/components/shared/Message.svelte"; import type { Artifact, DeployContractRequest, UpdateDeploymentRequest } from "$lib/models/deploy"; - import { getNetworkLiteral } from "$lib/models/network"; + import { getNetworkLiteral, isProductionNetwork } from "$lib/models/network"; import { attempt } from "$lib/utils/attempt"; import { getContractBytecode } from "$lib/utils/contracts"; import { deployContract, switchToNetwork } from "$lib/ethereum"; @@ -61,6 +61,15 @@ currentStep = step; } + const deploymentUrl = $derived( + deploymentId && globalState.form.network + ? `https://defender.openzeppelin.com/#/deploy/environment/${ + isProductionNetwork(globalState.form.network) ? 'production' : 'test' + }?deploymentId=${deploymentId}` + : undefined + ); + + const displayMessage = (message: string, type: "success" | "error") => { successMessage = ""; errorMessage = ""; @@ -294,7 +303,7 @@ } deploymentId = newDeploymentId; - displayMessage("Deployment successful", "success"); + displayMessage("Deployment successfuly created in Defender", "success"); }; async function compileAndDeploy() { @@ -343,6 +352,10 @@ {#if successMessage || errorMessage} + + {#if deploymentUrl} + @@ -337,7 +43,13 @@ {}} /> - @@ -346,16 +58,20 @@ - -
- +
+
+ +
+
From 0adbba5848405e00163c4a139289da3f71ced258 Mon Sep 17 00:00:00 2001 From: Marcos Date: Tue, 10 Dec 2024 16:28:50 -0300 Subject: [PATCH 3/5] add support to deterministic deployments --- src/lib/utils/helpers.ts | 6 +++ src/lib/wizard/components/Deploy.svelte | 53 +++++++++++++++++-- .../wizard/components/shared/Message.svelte | 8 ++- src/routes/wizard.svelte | 6 +-- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/lib/utils/helpers.ts b/src/lib/utils/helpers.ts index d32442a..4c0c918 100644 --- a/src/lib/utils/helpers.ts +++ b/src/lib/utils/helpers.ts @@ -14,3 +14,9 @@ export const isSameNetwork = (a: string | TenantNetworkResponse, b: string | Ten export const isDeploymentEnvironment = (approvalProcess: ApprovalProcess) => { return approvalProcess.component?.includes('deploy'); } + +export const isMultisig = (viaType?: ApprovalProcess['viaType']) => { + if (!viaType) return false; + const multisigTypes = ['Safe', 'Multisig', 'Gnosis Safe', 'Gnosis Multisig']; + return multisigTypes.includes(viaType); +} \ No newline at end of file diff --git a/src/lib/wizard/components/Deploy.svelte b/src/lib/wizard/components/Deploy.svelte index 9713e24..74501e2 100644 --- a/src/lib/wizard/components/Deploy.svelte +++ b/src/lib/wizard/components/Deploy.svelte @@ -9,11 +9,11 @@ import { addAPToDropdown, findDeploymentEnvironment, globalState } from "$lib/state/state.svelte"; import { attempt } from "$lib/utils/attempt"; import { encodeConstructorArgs, getConstructorInputsWizard, getContractBytecode } from "$lib/utils/contracts"; + import { isMultisig } from "$lib/utils/helpers"; import Button from "./shared/Button.svelte"; import Input from "./shared/Input.svelte"; import Message from "./shared/Message.svelte"; - let inputsWithValue = $state>({}); let busy = $state(false); let successMessage = $state(""); @@ -22,6 +22,8 @@ let compilationResult = $state<{ output: Artifact['output'] }>(); let deploymentId = $state(undefined); let deploymentResult = $state(undefined); + let isDeterministic = $state(false); + let salt: string = $state(""); let contractBytecode = $derived.by(() => { if (!globalState.contract?.target || !compilationResult) return; @@ -46,6 +48,12 @@ return getConstructorInputsWizard(globalState.contract?.target, compilationResult.output.contracts); }); + let enforceDeterministic = $derived.by(() => { + const selectedMultisig = globalState.form.approvalType === 'existing' && isMultisig(globalState.form.approvalProcessSelected?.viaType); + const toCreateMultisig = globalState.form.approvalType === 'new' && isMultisig(globalState.form.approvalProcessToCreate?.viaType); + return selectedMultisig || toCreateMultisig; + }); + const deploymentUrl = $derived( deploymentId && globalState.form.network ? `https://defender.openzeppelin.com/#/deploy/environment/${ @@ -82,7 +90,7 @@ compilationResult = res.data; } - const displayMessage = (message: string, type: "success" | "error") => { + function displayMessage(message: string, type: "success" | "error") { successMessage = ""; errorMessage = ""; if (type === "success") { @@ -92,6 +100,11 @@ } } + function handleSaltChanged(event: Event) { + const target = event.target as HTMLInputElement; + salt = target.value; + } + export async function handleInjectedProviderDeployment(bytecode: string) { // Switch network if needed const [, networkError] = await attempt(async () => switchToNetwork(globalState.form.network!)); @@ -201,6 +214,9 @@ return; } + errorMessage = ""; + successMessage = ""; + const [constructorBytecode, constructorError] = await encodeConstructorArgs(inputs, inputsWithValue); if (constructorError) { displayMessage(`Error encoding constructor arguments: ${constructorError.msg}`, "error"); @@ -246,9 +262,8 @@ verifySourceCode: true, licenseType: 'MIT', artifactPayload: JSON.stringify(deploymentArtifact), - // TODO: Implement constructor arguments + salt - constructorBytecode: '', - salt: '', + constructorBytecode, + salt, } const [newDeploymentId, deployError] = await attempt(async () => createDefenderDeployment(deployRequest)); @@ -286,6 +301,32 @@
+
+ (isDeterministic = !isDeterministic)} + disabled={enforceDeterministic} + > + + {#if enforceDeterministic} + + {/if} +
+ + {#if isDeterministic || enforceDeterministic} + + {/if} + {#if compilationError} {/if} @@ -295,6 +336,8 @@ {#each inputs as input} {/each} + {:else} + {/if}