Skip to content
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
8 changes: 8 additions & 0 deletions src/lib/models/solc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export type CompilerInput = {
*/
settings: {
outputSelection: Record<string, Record<string, string[]>>;
optimizer?: {
enabled: boolean,
runs: number,
},
};
};

Expand All @@ -26,6 +30,10 @@ export function buildCompilerInput(sources: ContractSources): CompilerInput {
sources,
language: 'Solidity',
settings: {
optimizer: {
enabled: true,
runs: 200,
},
outputSelection: {
'*': { '*': ['*'] }
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/remix/components/Deploy.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
contractBytecode = getContractBytecode(
contractInfo.path,
contractInfo.name,
globalState.contract.data
globalState.contract.data.contracts
);
}
});
Expand Down
4 changes: 2 additions & 2 deletions src/lib/utils/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export function createArtifactPayload(
export function getContractBytecode(
path: string,
contractName: string,
compilation: CompilationResult
contractSources: Record<string, any>
): string {
return compilation.contracts[path][contractName].evm.bytecode.object;
return contractSources[path][contractName].evm.bytecode.object;
}
8 changes: 4 additions & 4 deletions src/lib/wizard/components/ApprovalProcess.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { getNetworkLiteral } from "$lib/models/network";
import Input from "./shared/Input.svelte";

let address = $state<string>("");
let address = $state<string>(globalState.form.approvalProcessToCreate?.via || "");

function approvalProcessByNetworkAndComponent(ap: ApprovalProcess) {
const networkName = typeof globalState.form.network === 'string'
Expand Down Expand Up @@ -143,7 +143,7 @@
title={disableCreation ? "Deploy Environment already exists" : undefined}
/>
<label
class="text-sm"
class={`text-sm ${disableCreation ? 'text-gray-500' : ''}`}
for="flexRadioDefault2"
title={disableCreation ? "Deploy Environment already exists" : undefined}
>
Expand All @@ -163,7 +163,7 @@

{#if approvalProcessType === "EOA" || approvalProcessType === "Safe"}
<div class="mt-2">
<Input value={address} placeholder="* Address" type="text" />
<Input value={address} placeholder="* Address" type="text" onchange={onAddressChange} />
</div>
{:else if approvalProcessType === "Relayer"}
{#if disableRelayers}
Expand Down Expand Up @@ -197,7 +197,7 @@
disabled={disableCreation}
/>
<label
class="text-sm"
class={`text-sm ${disableCreation ? 'text-gray-500' : ''}`}
for="flexRadioDefault2"
title={disableCreation ? "Deploy Environment already exists" : undefined}
>
Expand Down
115 changes: 68 additions & 47 deletions src/lib/wizard/components/Configuration.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,77 +5,98 @@
import { globalState } from "$lib/state/state.svelte";
import Button from "./shared/Button.svelte";
import Input from "./shared/Input.svelte";
import Message from "./shared/Message.svelte";

let loading = $state(false);
let successMessage = $state<string | undefined>(undefined);
let errorMessage = $state<string | undefined>(undefined);
let apiKey = $state("");
let apiSecret = $state("");
let apiKey = $state(globalState.credentials?.apiKey ?? "");
let apiSecret = $state(globalState.credentials?.apiSecret ?? "");

function handleGetApiKey() {
// TODO: Implement
window.open(
"https://defender.openzeppelin.com/#/settings/api-keys",
"_blank",
);
}

async function authenticate() {

loading = true;

const result: APIResponse<AuthenticationResponse> = await API.authenticate({ apiKey, apiSecret });

if (result.success) {
globalState.authenticated = true;
successMessage = "API Key Authenticated";
} else {
errorMessage = result.error ?? "Defender Authentication Failed";
}

if (result?.data?.credentials) {
globalState.credentials = {
apiKey: result?.data?.credentials.apiKey,
apiSecret: result?.data?.credentials.apiSecret,
};
}

if (result?.data?.permissions) {
globalState.permissions = result?.data?.permissions;
}

if (result?.data?.networks) {
globalState.networks = result?.data?.networks;
}

if (result?.data?.approvalProcesses) {
globalState.approvalProcesses = result?.data?.approvalProcesses;
}

if (result?.data?.relayers) {
globalState.relayers = result?.data?.relayers;
}

loading = false;
loading = true;
successMessage = undefined;
errorMessage = undefined;

const result: APIResponse<AuthenticationResponse> = await API.authenticate({
apiKey,
apiSecret,
});

if (result.success) {
globalState.authenticated = true;
successMessage = "API Key Authenticated";
} else {
errorMessage = result.error ?? "Defender Authentication Failed";
}

if (result?.data?.credentials) {
globalState.credentials = {
apiKey: result?.data?.credentials.apiKey,
apiSecret: result?.data?.credentials.apiSecret,
};
}

if (result?.data?.permissions) {
globalState.permissions = result?.data?.permissions;
}

if (result?.data?.networks) {
globalState.networks = result?.data?.networks;
}

if (result?.data?.approvalProcesses) {
globalState.approvalProcesses = result?.data?.approvalProcesses;
}

if (result?.data?.relayers) {
globalState.relayers = result?.data?.relayers;
}

loading = false;
}

</script>

<div class="flex flex-col gap-2">
<div class="flex flex-row justify-between">
<div>
<label class="text-xs" for="apiKey">API Key</label>
<i class="fa fa-info-circle text-xs text-gray-500" title="Get your API key from the Defender Dashboard"></i>
<i
class="fa fa-info-circle text-xs text-gray-500"
title="Get your API key from the Defender Dashboard"
></i>
</div>
<button onclick={handleGetApiKey} class="text-xs text-blue-600 font-bold">Get API Key</button>
<button onclick={handleGetApiKey} class="text-xs text-blue-600 font-bold"
>Get API Key</button
>
</div>
<Input value={apiKey} placeholder="Enter your API key" type="text" />
<Input
bind:value={apiKey}
placeholder="Enter your API key"
type="text"
/>

<Input label="Secret" value={apiSecret} placeholder="Enter your API secret" type="password" />
<Input
label="Secret"
bind:value={apiSecret}
placeholder="Enter your API secret"
type="password"
/>

<Button loading={loading} label="Authenticate" onClick={authenticate} />
<Button {loading} label="Authenticate" onClick={authenticate} />

{#if successMessage}
<div class="text-green-600">{successMessage}</div>
<Message message={successMessage} type="success" />
{/if}

{#if errorMessage}
<div class="text-red-600">{errorMessage}</div>
<Message message={errorMessage} type="error" />
{/if}
</div>
5 changes: 3 additions & 2 deletions src/lib/wizard/components/shared/Button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
loading: boolean;
onClick: () => void;
label: string;
disabled?: boolean;
};
const { loading, onClick, label }: Props = $props();
const { loading, onClick, label, disabled }: Props = $props();
</script>

<button onclick={onClick} disabled={loading} class="bg-blue-600 text-white text-sm rounded-md p-2 mt-2" class:bg-gray-400={loading}>
<button onclick={onClick} disabled={disabled || loading} class="bg-blue-600 text-white text-sm rounded-md p-2 mt-2" class:bg-gray-400={loading}>
{#if loading}
<i class="fa fa-spinner fa-spin"></i>
{/if}
Expand Down
97 changes: 66 additions & 31 deletions src/lib/wizard/components/shared/Dropdown.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@
import type { DropdownItem } from "$lib/models/ui";
import { createEventDispatcher } from "svelte";

function clickOutside(node: HTMLElement, handler: () => void) {
const handleClick = (event: MouseEvent) => {
if (!node.contains(event.target as Node)) {
handler();
}
};

document.addEventListener('click', handleClick, true);

return {
destroy() {
document.removeEventListener('click', handleClick, true);
}
};
}

type Props = {
placeholder: string;
items: DropdownItem[];
Expand Down Expand Up @@ -31,39 +47,58 @@
selected = item;
dispatch("select", item);
};
let isOpen = $state(false);

const toggleDropdown = () => {
if (!disabled) isOpen = !isOpen;
};

const handleSelect = (item: DropdownItem) => {
selected = item;
isOpen = false;
dispatch("select", item);
};

const handleClickOutside = () => {
isOpen = false;
};
</script>

<div class="flex flex-col">
<select name={name} id={name} bind:value={selected} disabled={disabled} class="border border-gray-300 disabled:opacity-50 rounded-md cursor-pointer p-2 text-xs">
<option disabled selected value={undefined}>{placeholder}</option>
{#each Object.entries(groupedItems) as [group, items]}
{#if group !== 'default'}
<optgroup label={group}>
{#each items.sort((a, b) => a.label.localeCompare(b.label)) as item}
<option value={item.value} onclick={() => onSelect(item)}>{item.label}</option>
{/each}
</optgroup>
{:else}
<div class="relative w-full" use:clickOutside={handleClickOutside}>
<button
type="button"
class="w-full flex items-center justify-between border border-gray-300 disabled:opacity-50 rounded-md p-2 text-xs bg-white"
onclick={toggleDropdown}
disabled={disabled}
{name}
>
<span class="truncate">
{selected ? selected.label : placeholder}
</span>
<i class="fa fa-chevron-down text-[8px] transition-transform duration-200 font-light {isOpen ? 'rotate-180' : ''}"></i>
</button>

{#if isOpen}
<div class="absolute z-10 w-full mt-1 bg-white border border-gray-300 rounded-md shadow-lg max-h-60 overflow-auto">
{#each Object.entries(groupedItems) as [group, items]}
{#if group !== 'default'}
<div class="px-2 py-1 text-xs font-semibold bg-gray-50 text-gray-700">{group}</div>
{/if}
{#each items.sort((a, b) => a.label.localeCompare(b.label)) as item}
<option value={item.value} onclick={() => onSelect(item)}>{item.label}</option>
<button
type="button"
class="w-full text-left px-2 py-1.5 text-xs hover:bg-gray-100 focus:bg-gray-100 focus:outline-none {selected?.value === item.value ? 'bg-gray-50' : ''}"
onclick={() => handleSelect(item)}
>
{item.label}
</button>
{/each}
{/each}
{#if items.length === 0}
<div class="px-2 py-1.5 text-xs text-gray-500">
{emptyLabel ?? "No items available"}
</div>
{/if}
{/each}
{#if items.length === 0}
<option disabled>{emptyLabel ?? "No items available"}</option>
{/if}
</select>
</div>


<style>
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23000' d='M6 8l-6-6h12l-6 6z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 0.75rem center;
background-size: 8px 8px;
}
</style>
</div>
{/if}
</div>
16 changes: 14 additions & 2 deletions src/lib/wizard/components/shared/Input.svelte
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
<script lang="ts">
import type { ChangeEventHandler } from "svelte/elements";

type Props = {
label?: string;
value: string;
placeholder: string;
type: 'text' | 'password';
disabled?: boolean;
onchange?: ChangeEventHandler<HTMLInputElement>;
};
let { label, value, placeholder, type, disabled }: Props = $props();
let { label, value = $bindable(), placeholder, type, disabled, onchange }: Props = $props();

</script>

{#if label}
<label class="text-xs" for="apiSecret">{label}</label>
{/if}
<input name="apiSecret" type={type} bind:value={value} placeholder={placeholder} disabled={disabled} class="border text-xs border-gray-300 disabled:opacity-50 rounded-md p-2 w-full" />
<input
name="apiSecret"
type={type}
bind:value={value}
placeholder={placeholder}
disabled={disabled}
onchange={onchange}
class="border text-xs border-gray-300 disabled:opacity-50 rounded-md p-2 w-full"
/>
Loading
Loading