From 84b781078934cc368a733eb15ba72a111ec6b12f Mon Sep 17 00:00:00 2001 From: Marcos Date: Fri, 29 Nov 2024 19:25:50 -0300 Subject: [PATCH 01/34] add conditional mount --- src/lib/remix/index.ts | 2 +- src/routes/+page.svelte | 68 ++++++++++++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/lib/remix/index.ts b/src/lib/remix/index.ts index b97f542..f4ca0aa 100644 --- a/src/lib/remix/index.ts +++ b/src/lib/remix/index.ts @@ -4,7 +4,7 @@ import { listenOnThemeChanged } from "./theme"; import { listenOnCompilerResults } from "./compiler"; import { initLogger } from "./logger"; -export const initPlugin = () => { +export const initRemixPlugin = () => { const plugin = new PluginClient({ allowOrigins: ['https://remix.ethereum.org'] }); const client = createClient(plugin); diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index df960dc..cdd30c4 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,5 +1,5 @@
-

- To get started with Deploy With Defender, you need to - have an - OpenZeppelin Defender Account - (It's free) and setup an - + To get started with Deploy With Defender, you need to + have an + OpenZeppelin Defender Account + (It's free) and setup an + + API Key and Secret. - API Key and Secret. -

+

+ {/if} + + {#if parent === 'wizard'} +

Defender Deploy in Wizard

+ {/if} {#if globalState.error}
From 96e76d9af2e3b0e55602453a3ee4529696ef91b3 Mon Sep 17 00:00:00 2001 From: Marcos Date: Mon, 2 Dec 2024 18:25:34 -0300 Subject: [PATCH 02/34] split wizard from remix UI --- src/lib/remix/compiler.ts | 2 +- .../components/ApprovalProcess.svelte | 2 +- .../components/Deploy.svelte} | 2 +- src/lib/{ => remix}/components/Network.svelte | 2 +- src/lib/{ => remix}/components/Setup.svelte | 2 +- .../components/shared/Button.svelte | 0 .../components/shared/Dropdown.svelte | 0 src/lib/{ => remix}/state/state.svelte.ts | 0 src/lib/wizard/index.ts | 4 + src/routes/+page.svelte | 160 ++---------------- src/routes/remix.svelte | 142 ++++++++++++++++ src/routes/wizard.svelte | 4 + 12 files changed, 170 insertions(+), 150 deletions(-) rename src/lib/{ => remix}/components/ApprovalProcess.svelte (99%) rename src/lib/{components/Depoy.svelte => remix/components/Deploy.svelte} (99%) rename src/lib/{ => remix}/components/Network.svelte (96%) rename src/lib/{ => remix}/components/Setup.svelte (97%) rename src/lib/{ => remix}/components/shared/Button.svelte (100%) rename src/lib/{ => remix}/components/shared/Dropdown.svelte (100%) rename src/lib/{ => remix}/state/state.svelte.ts (100%) create mode 100644 src/lib/wizard/index.ts create mode 100644 src/routes/remix.svelte create mode 100644 src/routes/wizard.svelte diff --git a/src/lib/remix/compiler.ts b/src/lib/remix/compiler.ts index ab3233d..efeff24 100644 --- a/src/lib/remix/compiler.ts +++ b/src/lib/remix/compiler.ts @@ -1,4 +1,4 @@ -import { globalState } from "$lib/state/state.svelte"; +import { globalState } from "$lib/remix/state/state.svelte"; import type { PluginClient } from "@remixproject/plugin" import type { CompilationFileSources, CompilationResult, lastCompilationResult } from "@remixproject/plugin-api"; diff --git a/src/lib/components/ApprovalProcess.svelte b/src/lib/remix/components/ApprovalProcess.svelte similarity index 99% rename from src/lib/components/ApprovalProcess.svelte rename to src/lib/remix/components/ApprovalProcess.svelte index bb7f430..ae873a8 100644 --- a/src/lib/components/ApprovalProcess.svelte +++ b/src/lib/remix/components/ApprovalProcess.svelte @@ -1,5 +1,5 @@
- {#if parent === 'remix'} -

- To get started with Deploy With Defender, you need to - have an - OpenZeppelin Defender Account - (It's free) and setup an - - API Key and Secret. -

+ {#if parent === 'none'} +

⚠️ This page is meant to be embedded in an iframe! ⚠️

{/if} {#if parent === 'wizard'} -

Defender Deploy in Wizard

+ {/if} - {#if globalState.error} -
-

{globalState.error ?? ""}

-
+ {#if parent === 'remix'} + {/if} - -
- {#each [0, 1, 2, 3] as index} -
- - - {#if currentTab === index} -
-
- {#if index === 0} wait(1000).then(() => toggle(1))}/>{/if} - {#if index === 1} wait(1000).then(() => toggle(2))}/>{/if} - {#if index === 2}{/if} - {#if index === 3}{/if} -
-
- {/if} -
- {/each} -
- diff --git a/src/routes/remix.svelte b/src/routes/remix.svelte new file mode 100644 index 0000000..1ea85d3 --- /dev/null +++ b/src/routes/remix.svelte @@ -0,0 +1,142 @@ + + +

+ To get started with Deploy With Defender, you need to + have an + OpenZeppelin Defender Account + (It's free) and setup an + + API Key and Secret. +

+ +{#if globalState.error} +
+

{globalState.error ?? ""}

+
+{/if} + +
+ {#each [0, 1, 2, 3] as index} +
+ + + {#if currentTab === index} +
+
+ {#if index === 0} wait(1000).then(() => toggle(1))}/>{/if} + {#if index === 1} wait(1000).then(() => toggle(2))}/>{/if} + {#if index === 2}{/if} + {#if index === 3}{/if} +
+
+ {/if} +
+ {/each} +
+ + diff --git a/src/routes/wizard.svelte b/src/routes/wizard.svelte new file mode 100644 index 0000000..105abb4 --- /dev/null +++ b/src/routes/wizard.svelte @@ -0,0 +1,4 @@ + + +

Defender Deploy in Wizard

\ No newline at end of file From c79fc0c8798a2a59201999a8e59de4bdb1ca57bd Mon Sep 17 00:00:00 2001 From: Marcos Date: Tue, 3 Dec 2024 08:17:36 -0300 Subject: [PATCH 03/34] feat: install compiler and setup --- package.json | 3 +- pnpm-lock.yaml | 57 ++++++++++++++++++++++++++++++++++++++ src/lib/models/solc.ts | 20 +++++++++++++ src/lib/wizard/compiler.ts | 23 +++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 src/lib/models/solc.ts create mode 100644 src/lib/wizard/compiler.ts diff --git a/package.json b/package.json index ed54db7..5cc57b4 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@remixproject/plugin-utils": "^0.3.38", "@sveltejs/adapter-netlify": "^4.3.6", "bootstrap": "^5.3.3", - "ethers": "^6.13.4" + "ethers": "^6.13.4", + "solc": "^0.8.28" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fbd3b7e..927600d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: ethers: specifier: ^6.13.4 version: 6.13.4 + solc: + specifier: ^0.8.28 + version: 0.8.28 devDependencies: '@sveltejs/adapter-auto': specifier: ^3.0.0 @@ -660,6 +663,13 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + command-exists@1.2.9: + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} @@ -926,6 +936,10 @@ packages: magic-string@0.30.12: resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} + memorystream@0.3.1: + resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} + engines: {node: '>= 0.10.0'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -973,6 +987,10 @@ packages: encoding: optional: true + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -1027,6 +1045,10 @@ packages: safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + set-cookie-parser@2.7.1: resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} @@ -1053,6 +1075,11 @@ packages: resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} engines: {node: '>=18'} + solc@0.8.28: + resolution: {integrity: sha512-AFCiJ+b4RosyyNhnfdVH4ZR1+TxiL91iluPjw0EJslIu4LXGM9NYqi2z5y8TqochC4tcH9QsHfwWhOIC9jPDKA==} + engines: {node: '>=10.0.0'} + hasBin: true + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1091,6 +1118,10 @@ packages: tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -2048,6 +2079,10 @@ snapshots: dependencies: delayed-stream: 1.0.0 + command-exists@1.2.9: {} + + commander@8.3.0: {} + cookie@0.6.0: {} core-util-is@1.0.3: {} @@ -2330,6 +2365,8 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + memorystream@0.3.1: {} + mime-db@1.52.0: {} mime-types@2.1.35: @@ -2358,6 +2395,8 @@ snapshots: dependencies: whatwg-url: 5.0.0 + os-tmpdir@1.0.2: {} + package-json-from-dist@1.0.1: {} pako@1.0.11: {} @@ -2427,6 +2466,8 @@ snapshots: safe-buffer@5.1.2: {} + semver@5.7.2: {} + set-cookie-parser@2.7.1: {} set-function-length@1.2.2: @@ -2454,6 +2495,18 @@ snapshots: mrmime: 2.0.0 totalist: 3.0.1 + solc@0.8.28: + dependencies: + command-exists: 1.2.9 + commander: 8.3.0 + follow-redirects: 1.15.9 + js-sha3: 0.8.0 + memorystream: 0.3.1 + semver: 5.7.2 + tmp: 0.0.33 + transitivePeerDependencies: + - debug + source-map-js@1.2.1: {} string-width@4.2.3: @@ -2513,6 +2566,10 @@ snapshots: globalyzer: 0.1.0 globrex: 0.1.2 + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + totalist@3.0.1: {} tr46@0.0.3: {} diff --git a/src/lib/models/solc.ts b/src/lib/models/solc.ts new file mode 100644 index 0000000..f63b98d --- /dev/null +++ b/src/lib/models/solc.ts @@ -0,0 +1,20 @@ +export type CompilerInput = { + /** + * The language, currently only Solidity is supported. + */ + language: string; + /** + * Name of the file and the content of the file. + * e.g. { 'test.sol': { content: 'contract C { function f() public { L.f(); } }' } } + */ + sources: Record; + /** + * Settings for the compiler. + * e.g. { outputSelection: { '*': { '*': ['*'] } }" + */ + settings: { + outputSelection: Record>; + }; +}; + +export type ImportContents = Record; \ No newline at end of file diff --git a/src/lib/wizard/compiler.ts b/src/lib/wizard/compiler.ts new file mode 100644 index 0000000..ed0f5cc --- /dev/null +++ b/src/lib/wizard/compiler.ts @@ -0,0 +1,23 @@ +const solc = require('solc'); + +import type { ImportContents } from "$lib/models/solc"; +import type { CompilerInput } from "$lib/models/solc"; + +export class SolidityCompiler { + getContent(path: string, contents: Record) { + if (contents[path]) { + return contents[path]; + } + return { error: 'File not found' }; + } + + compile(input: CompilerInput, contents: ImportContents) { + const findImports = (path: string) => this.getContent(path, contents); + const output = solc.compile(JSON.stringify(input), { import: findImports }); + return output; + } +} + +export const Compiler = new SolidityCompiler(); + + From 39bceb83d1c544271d4d5d0cd1ec02a7fc416770 Mon Sep 17 00:00:00 2001 From: Marcos Date: Tue, 3 Dec 2024 09:29:03 -0300 Subject: [PATCH 04/34] feat: add support to solidity compiler --- src/app.d.ts | 5 +++++ src/lib/api.ts | 11 +++++++++++ src/lib/wizard/compiler.ts | 23 ----------------------- src/lib/wizard/index.ts | 4 +--- src/routes/compiler/+server.ts | 19 +++++++++++++++++++ src/routes/compiler/compiler.ts | 20 ++++++++++++++++++++ src/routes/wizard.svelte | 6 +++++- 7 files changed, 61 insertions(+), 27 deletions(-) delete mode 100644 src/lib/wizard/compiler.ts create mode 100644 src/routes/compiler/+server.ts create mode 100644 src/routes/compiler/compiler.ts diff --git a/src/app.d.ts b/src/app.d.ts index ad92508..f122aeb 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -13,3 +13,8 @@ declare global { declare interface Window { ethereum?: import('ethers').Eip1193Provider & import('ethers').BrowserProvider; } + +// solc does not have a type definition file. +declare module 'solc' { + export function compile(input: string, opts?: any): any; +} \ No newline at end of file diff --git a/src/lib/api.ts b/src/lib/api.ts index 38a29c4..26180f0 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,6 +1,7 @@ import type { CreateApprovalProcessRequest } from "./models/approval-process"; import type { Credentials } from "./models/auth"; import type { DeployContractRequest, UpdateDeploymentRequest } from "./models/deploy"; +import type { CompilerInput } from "./models/solc"; class ApiClient { credentials: Credentials | null = null; @@ -72,6 +73,16 @@ class ApiClient { return response.json(); } + + async compile(input: CompilerInput) { + const response = await fetch("/compiler", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ input }), + }); + + return response.json(); + } } export const API = new ApiClient(); diff --git a/src/lib/wizard/compiler.ts b/src/lib/wizard/compiler.ts deleted file mode 100644 index ed0f5cc..0000000 --- a/src/lib/wizard/compiler.ts +++ /dev/null @@ -1,23 +0,0 @@ -const solc = require('solc'); - -import type { ImportContents } from "$lib/models/solc"; -import type { CompilerInput } from "$lib/models/solc"; - -export class SolidityCompiler { - getContent(path: string, contents: Record) { - if (contents[path]) { - return contents[path]; - } - return { error: 'File not found' }; - } - - compile(input: CompilerInput, contents: ImportContents) { - const findImports = (path: string) => this.getContent(path, contents); - const output = solc.compile(JSON.stringify(input), { import: findImports }); - return output; - } -} - -export const Compiler = new SolidityCompiler(); - - diff --git a/src/lib/wizard/index.ts b/src/lib/wizard/index.ts index eba0485..53ea232 100644 --- a/src/lib/wizard/index.ts +++ b/src/lib/wizard/index.ts @@ -1,4 +1,2 @@ export const initWizardPlugin = () => { - // when users configure a contract, the plugin gets the results. - // listenToContracts(); -} +} \ No newline at end of file diff --git a/src/routes/compiler/+server.ts b/src/routes/compiler/+server.ts new file mode 100644 index 0000000..09a1d47 --- /dev/null +++ b/src/routes/compiler/+server.ts @@ -0,0 +1,19 @@ +import type { CompilerInput } from "$lib/models/solc"; +import { json } from '@sveltejs/kit'; +import { SolidityCompiler } from "./compiler"; +import { attempt } from "$lib/utils/attempt"; + + +export async function POST({ request }: { request: Request }) { + const { input }: { input: CompilerInput } = await request.json(); + + const compiler = new SolidityCompiler(); + + const [output, error] = await attempt(() => JSON.parse(compiler.compile(input))); + + if (error) { + return json({ success: false, error: error.msg }); + } + + return json({ success: true, data: { output } }); +} \ No newline at end of file diff --git a/src/routes/compiler/compiler.ts b/src/routes/compiler/compiler.ts new file mode 100644 index 0000000..55cc516 --- /dev/null +++ b/src/routes/compiler/compiler.ts @@ -0,0 +1,20 @@ +import solc from 'solc'; + +import type { ImportContents } from "$lib/models/solc"; +import type { CompilerInput } from "$lib/models/solc"; + +export class SolidityCompiler { + getContent(path: string, contents: Record) { + if (contents[path]) { + return contents[path]; + } + return { error: 'File not found' }; + } + + compile(input: CompilerInput, contents?: ImportContents) { + const shouldFindImports = contents !== undefined; + const findImports = (path: string) => shouldFindImports ? this.getContent(path, contents) : undefined; + const output = solc.compile(JSON.stringify(input), shouldFindImports ? { import: findImports } : undefined); + return output; + } +} diff --git a/src/routes/wizard.svelte b/src/routes/wizard.svelte index 105abb4..01cc9b5 100644 --- a/src/routes/wizard.svelte +++ b/src/routes/wizard.svelte @@ -1,4 +1,8 @@ -

Defender Deploy in Wizard

\ No newline at end of file +

Defender Deploy in Wizard

From ecd01cccff0bf99daf43c947c5a0b681d9d2d848 Mon Sep 17 00:00:00 2001 From: Marcos Date: Tue, 3 Dec 2024 09:32:10 -0300 Subject: [PATCH 05/34] fmt --- src/lib/models/solc.ts | 2 +- src/lib/wizard/index.ts | 2 +- src/routes/compiler/+server.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/models/solc.ts b/src/lib/models/solc.ts index f63b98d..d7a3c25 100644 --- a/src/lib/models/solc.ts +++ b/src/lib/models/solc.ts @@ -17,4 +17,4 @@ export type CompilerInput = { }; }; -export type ImportContents = Record; \ No newline at end of file +export type ImportContents = Record; diff --git a/src/lib/wizard/index.ts b/src/lib/wizard/index.ts index 53ea232..01cde03 100644 --- a/src/lib/wizard/index.ts +++ b/src/lib/wizard/index.ts @@ -1,2 +1,2 @@ export const initWizardPlugin = () => { -} \ No newline at end of file +} diff --git a/src/routes/compiler/+server.ts b/src/routes/compiler/+server.ts index 09a1d47..fcb0260 100644 --- a/src/routes/compiler/+server.ts +++ b/src/routes/compiler/+server.ts @@ -16,4 +16,4 @@ export async function POST({ request }: { request: Request }) { } return json({ success: true, data: { output } }); -} \ No newline at end of file +} From 9ce364f150b5853d54fb91e5a13186129a279ba5 Mon Sep 17 00:00:00 2001 From: Marcos Date: Tue, 3 Dec 2024 09:34:17 -0300 Subject: [PATCH 06/34] fmt --- src/app.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.d.ts b/src/app.d.ts index f122aeb..e2c24df 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -17,4 +17,4 @@ declare interface Window { // solc does not have a type definition file. declare module 'solc' { export function compile(input: string, opts?: any): any; -} \ No newline at end of file +} From 847d7e96431540a63f41b4c31207ddb84457ebf3 Mon Sep 17 00:00:00 2001 From: Marcos Date: Tue, 3 Dec 2024 15:38:49 -0300 Subject: [PATCH 07/34] feat: listen to wizard changes --- src/lib/wizard/components/Configure.svelte | 9 +++ src/lib/wizard/index.ts | 13 +++- src/lib/wizard/models/contract.ts | 76 ++++++++++++++++++++++ src/lib/wizard/state.svelte.ts | 6 ++ src/routes/+page.svelte | 15 ++--- src/routes/remix.svelte | 4 ++ src/routes/wizard.svelte | 7 +- 7 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 src/lib/wizard/components/Configure.svelte create mode 100644 src/lib/wizard/models/contract.ts create mode 100644 src/lib/wizard/state.svelte.ts diff --git a/src/lib/wizard/components/Configure.svelte b/src/lib/wizard/components/Configure.svelte new file mode 100644 index 0000000..b62fc13 --- /dev/null +++ b/src/lib/wizard/components/Configure.svelte @@ -0,0 +1,9 @@ + + + +

+ Contract: {JSON.stringify(wizardState.contract, null, 2)} +

diff --git a/src/lib/wizard/index.ts b/src/lib/wizard/index.ts index eba0485..cf783fc 100644 --- a/src/lib/wizard/index.ts +++ b/src/lib/wizard/index.ts @@ -1,4 +1,15 @@ +import type { DefenderDeployMessage } from "./models/contract"; +import { globalState } from "./state.svelte"; + export const initWizardPlugin = () => { // when users configure a contract, the plugin gets the results. - // listenToContracts(); + listenToContracts(); +} + +function listenToContracts() { + window.addEventListener('message', function (e: MessageEvent) { + if (e.data.kind === 'oz-wizard-defender-deploy') { + globalState.contract = e.data.contract; + } + }); } diff --git a/src/lib/wizard/models/contract.ts b/src/lib/wizard/models/contract.ts new file mode 100644 index 0000000..bf524fc --- /dev/null +++ b/src/lib/wizard/models/contract.ts @@ -0,0 +1,76 @@ +/** + * Interfaces for the contract object returned by the wizard. + */ + +export interface Contract { + name: string; + license: string; + parents: Parent[]; + natspecTags: NatspecTag[]; + imports: ImportContract[]; + functions: ContractFunction[]; + constructorCode: string[]; + constructorArgs: FunctionArgument[]; + variables: string[]; + upgradeable: boolean; +} + +export interface NatspecTag { + key: string; + value: string; +} + +export type Value = string | number | { lit: string } | { note: string, value: Value }; + +export interface Parent { + contract: ImportContract; + params: Value[]; + importOnly?: boolean; +} + +export interface ImportContract extends ReferencedContract { + path: string; +} + +export interface ReferencedContract { + name: string; + transpiled?: boolean; +} + +export interface Using { + library: ImportContract; + usingFor: string; +} + +export interface BaseFunction { + name: string; + args: FunctionArgument[]; + returns?: string[]; + kind: FunctionKind; + mutability?: FunctionMutability; +} + +export interface ContractFunction extends BaseFunction { + override: Set; + modifiers: string[]; + code: string[]; + mutability: FunctionMutability; + final: boolean; + comments: string[]; +} + +export type FunctionKind = 'internal' | 'public'; +export type FunctionMutability = typeof mutabilityRank[number]; + +// Order is important +const mutabilityRank = ['pure', 'view', 'nonpayable', 'payable'] as const; + +export interface FunctionArgument { + type: string | ReferencedContract; + name: string; +} + +export interface DefenderDeployMessage { + kind: 'oz-wizard-defender-deploy'; + contract: Contract; +} diff --git a/src/lib/wizard/state.svelte.ts b/src/lib/wizard/state.svelte.ts new file mode 100644 index 0000000..3c60954 --- /dev/null +++ b/src/lib/wizard/state.svelte.ts @@ -0,0 +1,6 @@ + +import type { Contract } from "./models/contract"; + +export const wizardState = $state<{ contract: Contract | undefined }>({ + contract: undefined, +}); diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 51c8760..9703914 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -20,20 +20,17 @@ // assumes that when in dev mode and // the ancestor origin is localhost, we are in the wizard if (dev && ancestorOrigin.includes("localhost")) { - parent = 'wizard'; - return; + return parent = 'wizard'; } - if (ancestorOrigin.includes("remix.ethereum")) { - parent = 'remix'; - return initRemixPlugin(); + if (ancestorOrigin.includes("wizard.openzeppelin")) { + return parent = 'wizard'; } - if (ancestorOrigin.includes("wizard.openzeppelin")) { - parent = 'wizard'; - // TODO: init wizard plugin - return; + if (ancestorOrigin.includes("remix.ethereum")) { + return parent = 'remix'; } + }); diff --git a/src/routes/remix.svelte b/src/routes/remix.svelte index a36362f..6e704fc 100644 --- a/src/routes/remix.svelte +++ b/src/routes/remix.svelte @@ -1,4 +1,6 @@

diff --git a/src/routes/wizard.svelte b/src/routes/wizard.svelte index 105abb4..d6faccd 100644 --- a/src/routes/wizard.svelte +++ b/src/routes/wizard.svelte @@ -1,4 +1,9 @@ -

Defender Deploy in Wizard

\ No newline at end of file + From 1505a17d0ba1dcdb2d6feb60aff497eb3867a281 Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 4 Dec 2024 10:15:11 -0300 Subject: [PATCH 08/34] change contract sources interface --- src/lib/api.ts | 1 + src/lib/wizard/components/Configure.svelte | 14 +++- src/lib/wizard/index.ts | 11 +++- src/lib/wizard/models/contract.ts | 76 ---------------------- src/lib/wizard/models/sources.ts | 12 ++++ src/lib/wizard/state.svelte.ts | 6 +- 6 files changed, 36 insertions(+), 84 deletions(-) delete mode 100644 src/lib/wizard/models/contract.ts create mode 100644 src/lib/wizard/models/sources.ts diff --git a/src/lib/api.ts b/src/lib/api.ts index 38a29c4..0ccf40a 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,6 +1,7 @@ import type { CreateApprovalProcessRequest } from "./models/approval-process"; import type { Credentials } from "./models/auth"; import type { DeployContractRequest, UpdateDeploymentRequest } from "./models/deploy"; +import type { ContractSources } from "./wizard/models/sources"; class ApiClient { credentials: Credentials | null = null; diff --git a/src/lib/wizard/components/Configure.svelte b/src/lib/wizard/components/Configure.svelte index b62fc13..97015bc 100644 --- a/src/lib/wizard/components/Configure.svelte +++ b/src/lib/wizard/components/Configure.svelte @@ -1,9 +1,19 @@ + async function compile() { + // if (!wizardState.sources) return; + // const result = await API.compile(wizardState.sources); + // console.log(result); + } +

- Contract: {JSON.stringify(wizardState.contract, null, 2)} + Contract to compile: {wizardState.sources?.target} + +

diff --git a/src/lib/wizard/index.ts b/src/lib/wizard/index.ts index cf783fc..c39e2da 100644 --- a/src/lib/wizard/index.ts +++ b/src/lib/wizard/index.ts @@ -1,5 +1,10 @@ -import type { DefenderDeployMessage } from "./models/contract"; -import { globalState } from "./state.svelte"; +import type { ContractSources } from "./models/sources"; +import { wizardState } from "./state.svelte"; + +export interface DefenderDeployMessage { + kind: 'oz-wizard-defender-deploy'; + sources: ContractSources; +} export const initWizardPlugin = () => { // when users configure a contract, the plugin gets the results. @@ -9,7 +14,7 @@ export const initWizardPlugin = () => { function listenToContracts() { window.addEventListener('message', function (e: MessageEvent) { if (e.data.kind === 'oz-wizard-defender-deploy') { - globalState.contract = e.data.contract; + wizardState.sources = e.data.sources; } }); } diff --git a/src/lib/wizard/models/contract.ts b/src/lib/wizard/models/contract.ts deleted file mode 100644 index bf524fc..0000000 --- a/src/lib/wizard/models/contract.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Interfaces for the contract object returned by the wizard. - */ - -export interface Contract { - name: string; - license: string; - parents: Parent[]; - natspecTags: NatspecTag[]; - imports: ImportContract[]; - functions: ContractFunction[]; - constructorCode: string[]; - constructorArgs: FunctionArgument[]; - variables: string[]; - upgradeable: boolean; -} - -export interface NatspecTag { - key: string; - value: string; -} - -export type Value = string | number | { lit: string } | { note: string, value: Value }; - -export interface Parent { - contract: ImportContract; - params: Value[]; - importOnly?: boolean; -} - -export interface ImportContract extends ReferencedContract { - path: string; -} - -export interface ReferencedContract { - name: string; - transpiled?: boolean; -} - -export interface Using { - library: ImportContract; - usingFor: string; -} - -export interface BaseFunction { - name: string; - args: FunctionArgument[]; - returns?: string[]; - kind: FunctionKind; - mutability?: FunctionMutability; -} - -export interface ContractFunction extends BaseFunction { - override: Set; - modifiers: string[]; - code: string[]; - mutability: FunctionMutability; - final: boolean; - comments: string[]; -} - -export type FunctionKind = 'internal' | 'public'; -export type FunctionMutability = typeof mutabilityRank[number]; - -// Order is important -const mutabilityRank = ['pure', 'view', 'nonpayable', 'payable'] as const; - -export interface FunctionArgument { - type: string | ReferencedContract; - name: string; -} - -export interface DefenderDeployMessage { - kind: 'oz-wizard-defender-deploy'; - contract: Contract; -} diff --git a/src/lib/wizard/models/sources.ts b/src/lib/wizard/models/sources.ts new file mode 100644 index 0000000..adde68f --- /dev/null +++ b/src/lib/wizard/models/sources.ts @@ -0,0 +1,12 @@ + + +export interface ContractSources { + target: string; + sources: SolcInputSources; +} + +export interface SolcInputSources { + [source: string]: { + content: string; + }; +} \ No newline at end of file diff --git a/src/lib/wizard/state.svelte.ts b/src/lib/wizard/state.svelte.ts index 3c60954..d5c9a40 100644 --- a/src/lib/wizard/state.svelte.ts +++ b/src/lib/wizard/state.svelte.ts @@ -1,6 +1,6 @@ -import type { Contract } from "./models/contract"; +import type { ContractSources } from "./models/sources"; -export const wizardState = $state<{ contract: Contract | undefined }>({ - contract: undefined, +export const wizardState = $state<{ sources: ContractSources | undefined }>({ + sources: undefined, }); From 492c6703dc26d8c59f70389e13786fc730c067da Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 4 Dec 2024 11:58:32 -0300 Subject: [PATCH 09/34] fix: load contract to compile --- src/lib/wizard/components/Configure.svelte | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/lib/wizard/components/Configure.svelte b/src/lib/wizard/components/Configure.svelte index 5557dfb..e9eb6b9 100644 --- a/src/lib/wizard/components/Configure.svelte +++ b/src/lib/wizard/components/Configure.svelte @@ -1,24 +1,27 @@

- Contract to compile: {wizardState.sources?.target} + Contract to compile: {getMainContractName(wizardState.sources)} - - result: {JSON.stringify(result, null, 2)}

From 03083036f3d507f222f376132ae0ea78e7f364cf Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 4 Dec 2024 16:29:35 -0300 Subject: [PATCH 10/34] add support to tailwind + add initial styles --- package.json | 3 + pnpm-lock.yaml | 609 +++++++++++++++++- postcss.config.js | 6 + .../wizard/components/Configuration.svelte | 53 ++ src/lib/wizard/components/Configure.svelte | 27 - src/lib/wizard/components/Network.svelte | 19 + .../wizard/components/shared/Dropdown.svelte | 61 ++ src/lib/wizard/state.svelte.ts | 4 +- src/routes/+page.svelte | 11 +- src/routes/wizard.svelte | 47 +- src/wizard-app.css | 3 + tailwind.config.js | 9 + 12 files changed, 811 insertions(+), 41 deletions(-) create mode 100644 postcss.config.js create mode 100644 src/lib/wizard/components/Configuration.svelte delete mode 100644 src/lib/wizard/components/Configure.svelte create mode 100644 src/lib/wizard/components/Network.svelte create mode 100644 src/lib/wizard/components/shared/Dropdown.svelte create mode 100644 src/wizard-app.css create mode 100644 tailwind.config.js diff --git a/package.json b/package.json index 5cc57b4..dbe9cb2 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,11 @@ "@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/kit": "^2.0.0", "@sveltejs/vite-plugin-svelte": "^4.0.0", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.49", "svelte": "^5.0.0", "svelte-check": "^4.0.0", + "tailwindcss": "^3.4.16", "typescript": "^5.0.0", "vite": "^5.0.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 927600d..dabf56c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,12 +45,21 @@ importers: '@sveltejs/vite-plugin-svelte': specifier: ^4.0.0 version: 4.0.0(svelte@5.1.6)(vite@5.4.10(@types/node@22.9.0)) + autoprefixer: + specifier: ^10.4.20 + version: 10.4.20(postcss@8.4.49) + postcss: + specifier: ^8.4.49 + version: 8.4.49 svelte: specifier: ^5.0.0 version: 5.1.6 svelte-check: specifier: ^4.0.0 version: 4.0.5(svelte@5.1.6)(typescript@5.6.3) + tailwindcss: + specifier: ^3.4.16 + version: 3.4.16 typescript: specifier: ^5.0.0 version: 5.6.3 @@ -66,6 +75,10 @@ packages: '@adraffy/ens-normalize@1.11.0': resolution: {integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==} + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -333,6 +346,18 @@ packages: resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + '@openzeppelin/defender-sdk-account-client@1.15.2': resolution: {integrity: sha512-lhYf1rBtac1MBbKP/ALgkjUhVulqo45RtaemTP9xI6BwUCCb4nq2SSKM82UN5sOE2I+VXSbPXf8w91bao5Mmmg==} @@ -383,6 +408,10 @@ packages: '@openzeppelin/defender-sdk@1.15.2': resolution: {integrity: sha512-Pt7MR+kzhsBfEQvW/cAOgLGb498x3Oq91G15GQ+g+cl978IpQgqx8rneZPv3aoQE5ipIk6EtWJlOl+tIAARKVg==} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@polka/url@1.0.0-next.28': resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} @@ -594,6 +623,16 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -604,6 +643,13 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.4.20: + resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -624,6 +670,10 @@ packages: bech32@1.1.4: resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + bn.js@4.12.0: resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} @@ -638,9 +688,18 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + brorand@1.1.0: resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + browserslist@4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer@4.9.2: resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} @@ -648,6 +707,17 @@ packages: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + caniuse-lite@1.0.30001686: + resolution: {integrity: sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + chokidar@4.0.1: resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} engines: {node: '>= 14.16.0'} @@ -666,6 +736,10 @@ packages: command-exists@1.2.9: resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + commander@8.3.0: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} @@ -689,6 +763,11 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -713,6 +792,12 @@ packages: devalue@5.1.1: resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dotenv@16.4.5: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} @@ -720,6 +805,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + electron-to-chromium@1.5.68: + resolution: {integrity: sha512-FgMdJlma0OzUYlbrtZ4AeXjKxKPk6KT8WOP8BjcqxWtlg8qyJQjRzPJzUtUn5GBg1oQ26hFs7HOOHJMYiJRnvQ==} + elliptic@6.5.4: resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} @@ -742,6 +830,10 @@ packages: engines: {node: '>=12'} hasBin: true + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + esm-env@1.1.4: resolution: {integrity: sha512-oO82nKPHKkzIj/hbtuDYy/JHqBHFlMIW36SDiPCVsj87ntDLcWN+sJ1erdVryd4NxODacFTsdrIE3b7IamqbOg==} @@ -765,6 +857,13 @@ packages: fast-base64-decode@1.0.0: resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fdir@6.4.2: resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} peerDependencies: @@ -773,6 +872,10 @@ packages: picomatch: optional: true + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + follow-redirects@1.15.9: resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} engines: {node: '>=4.0'} @@ -793,6 +896,9 @@ packages: resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fs-extra@11.2.0: resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} engines: {node: '>=14.14'} @@ -809,6 +915,18 @@ packages: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + glob@11.0.0: resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} engines: {node: 20 || >=22} @@ -867,10 +985,22 @@ packages: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -879,6 +1009,14 @@ packages: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + is-reference@3.0.2: resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} @@ -900,10 +1038,17 @@ packages: peerDependencies: ws: '*' + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.0.2: resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==} engines: {node: 20 || >=22} + jiti@1.21.6: + resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} + hasBin: true + js-cookie@2.2.1: resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} @@ -923,12 +1068,22 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + locate-character@3.0.0: resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.0.2: resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==} engines: {node: 20 || >=22} @@ -940,6 +1095,14 @@ packages: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -958,6 +1121,10 @@ packages: resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} engines: {node: 20 || >=22} + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} @@ -973,6 +1140,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -987,6 +1157,25 @@ packages: encoding: optional: true + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} @@ -1001,6 +1190,13 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.0: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} @@ -1008,12 +1204,61 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} - postcss@8.4.47: - resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.0.1: + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} process-nextick-args@2.0.1: @@ -1022,22 +1267,43 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + readdirp@4.0.2: resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} engines: {node: '>= 14.16.0'} + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rollup@4.24.3: resolution: {integrity: sha512-HBW896xR5HGmoksbi3JBDtmVzWiPAYqp7wip50hjQ67JbDz61nyoMPdqu1DvVW9asYb2M65Z20ZHsyJCMqMyDg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -1103,6 +1369,15 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + svelte-check@4.0.5: resolution: {integrity: sha512-icBTBZ3ibBaywbXUat3cK6hB5Du+Kq9Z8CRuyLmm64XIe2/r+lQcbuBx/IQgsbrC+kT2jQ0weVpZSSRIPwB6jQ==} engines: {node: '>= 18.0.0'} @@ -1115,6 +1390,18 @@ packages: resolution: {integrity: sha512-bYS/DpkqXk0j5UZgiNXrEjZYPRZ4Ncd87w4KUSbcZGyojA0+i/Ls9OGUjETHmdLe8RcQ0G8SX/T0PypPpAA/ew==} engines: {node: '>=18'} + tailwindcss@3.4.16: + resolution: {integrity: sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==} + engines: {node: '>=14.0.0'} + hasBin: true + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} @@ -1122,6 +1409,10 @@ packages: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -1129,6 +1420,9 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -1156,6 +1450,12 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -1336,6 +1636,11 @@ packages: utf-8-validate: optional: true + yaml@2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} + engines: {node: '>= 14'} + hasBin: true + zimmerframe@1.1.2: resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} @@ -1348,6 +1653,8 @@ snapshots: '@adraffy/ens-normalize@1.11.0': {} + '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -1640,6 +1947,18 @@ snapshots: '@noble/hashes@1.4.0': {} + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + '@openzeppelin/defender-sdk-account-client@1.15.2': dependencies: '@openzeppelin/defender-sdk-base-client': 1.15.2 @@ -1812,6 +2131,9 @@ snapshots: - web3-core - web3-utils + '@pkgjs/parseargs@0.11.0': + optional: true + '@polka/url@1.0.0-next.28': {} '@popperjs/core@2.11.8': {} @@ -2009,6 +2331,15 @@ snapshots: ansi-styles@6.2.1: {} + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + aria-query@5.3.2: {} async-retry@1.3.3: @@ -2017,6 +2348,16 @@ snapshots: asynckit@0.4.0: {} + autoprefixer@10.4.20(postcss@8.4.49): + dependencies: + browserslist: 4.24.2 + caniuse-lite: 1.0.30001686 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.4.49 + postcss-value-parser: 4.2.0 + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 @@ -2037,6 +2378,8 @@ snapshots: bech32@1.1.4: {} + binary-extensions@2.3.0: {} + bn.js@4.12.0: {} bn.js@5.2.1: {} @@ -2049,8 +2392,19 @@ snapshots: dependencies: balanced-match: 1.0.2 + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + brorand@1.1.0: {} + browserslist@4.24.2: + dependencies: + caniuse-lite: 1.0.30001686 + electron-to-chromium: 1.5.68 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.2) + buffer@4.9.2: dependencies: base64-js: 1.5.1 @@ -2065,6 +2419,22 @@ snapshots: get-intrinsic: 1.2.4 set-function-length: 1.2.2 + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001686: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + chokidar@4.0.1: dependencies: readdirp: 4.0.2 @@ -2081,6 +2451,8 @@ snapshots: command-exists@1.2.9: {} + commander@4.1.1: {} + commander@8.3.0: {} cookie@0.6.0: {} @@ -2101,6 +2473,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + cssesc@3.0.0: {} + debug@4.3.7: dependencies: ms: 2.1.3 @@ -2117,10 +2491,16 @@ snapshots: devalue@5.1.1: {} + didyoumean@1.2.2: {} + + dlv@1.1.3: {} + dotenv@16.4.5: {} eastasianwidth@0.2.0: {} + electron-to-chromium@1.5.68: {} + elliptic@6.5.4: dependencies: bn.js: 4.12.0 @@ -2167,6 +2547,8 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 + escalade@3.2.0: {} + esm-env@1.1.4: {} esrap@1.2.2: @@ -2200,8 +2582,24 @@ snapshots: fast-base64-decode@1.0.0: {} + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + fdir@6.4.2: {} + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + follow-redirects@1.15.9: {} for-each@0.3.3: @@ -2219,6 +2617,8 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 + fraction.js@4.3.7: {} + fs-extra@11.2.0: dependencies: graceful-fs: 4.2.11 @@ -2238,6 +2638,23 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.2 + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + glob@11.0.0: dependencies: foreground-child: 3.3.0 @@ -2297,14 +2714,30 @@ snapshots: call-bind: 1.0.7 has-tostringtag: 1.0.2 + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + is-callable@1.2.7: {} + is-core-module@2.15.1: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} is-generator-function@1.0.10: dependencies: has-tostringtag: 1.0.2 + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + is-reference@3.0.2: dependencies: '@types/estree': 1.0.6 @@ -2328,10 +2761,18 @@ snapshots: dependencies: ws: 8.18.0 + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jackspeak@4.0.2: dependencies: '@isaacs/cliui': 8.0.2 + jiti@1.21.6: {} + js-cookie@2.2.1: {} js-sha3@0.8.0: {} @@ -2355,10 +2796,16 @@ snapshots: dependencies: immediate: 3.0.6 + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + locate-character@3.0.0: {} lodash@4.17.21: {} + lru-cache@10.4.3: {} + lru-cache@11.0.2: {} magic-string@0.30.12: @@ -2367,6 +2814,13 @@ snapshots: memorystream@0.3.1: {} + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + mime-db@1.52.0: {} mime-types@2.1.35: @@ -2381,6 +2835,10 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + minipass@7.1.2: {} mri@1.2.0: {} @@ -2389,12 +2847,28 @@ snapshots: ms@2.1.3: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nanoid@3.3.7: {} node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + node-releases@2.0.18: {} + + normalize-path@3.0.0: {} + + normalize-range@0.1.2: {} + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + os-tmpdir@1.0.2: {} package-json-from-dist@1.0.1: {} @@ -2403,6 +2877,13 @@ snapshots: path-key@3.1.1: {} + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + path-scurry@2.0.0: dependencies: lru-cache: 11.0.2 @@ -2410,9 +2891,46 @@ snapshots: picocolors@1.1.1: {} + picomatch@2.3.1: {} + + pify@2.3.0: {} + + pirates@4.0.6: {} + possible-typed-array-names@1.0.0: {} - postcss@8.4.47: + postcss-import@15.1.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + + postcss-js@4.0.1(postcss@8.4.49): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.49 + + postcss-load-config@4.0.2(postcss@8.4.49): + dependencies: + lilconfig: 3.1.3 + yaml: 2.6.1 + optionalDependencies: + postcss: 8.4.49 + + postcss-nested@6.2.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.4.49: dependencies: nanoid: 3.3.7 picocolors: 1.1.1 @@ -2422,6 +2940,12 @@ snapshots: proxy-from-env@1.1.0: {} + queue-microtask@1.2.3: {} + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -2432,10 +2956,22 @@ snapshots: string_decoder: 1.1.1 util-deprecate: 1.0.2 + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + readdirp@4.0.2: {} + resolve@1.22.8: + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + retry@0.13.1: {} + reusify@1.0.4: {} + rollup@4.24.3: dependencies: '@types/estree': 1.0.6 @@ -2460,6 +2996,10 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.24.3 fsevents: 2.3.3 + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + sade@1.8.1: dependencies: mri: 1.2.0 @@ -2533,6 +3073,18 @@ snapshots: dependencies: ansi-regex: 6.1.0 + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + + supports-preserve-symlinks-flag@1.0.0: {} + svelte-check@4.0.5(svelte@5.1.6)(typescript@5.6.3): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -2561,6 +3113,41 @@ snapshots: magic-string: 0.30.12 zimmerframe: 1.1.2 + tailwindcss@3.4.16: + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.6 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.4.49 + postcss-import: 15.1.0(postcss@8.4.49) + postcss-js: 4.0.1(postcss@8.4.49) + postcss-load-config: 4.0.2(postcss@8.4.49) + postcss-nested: 6.2.0(postcss@8.4.49) + postcss-selector-parser: 6.1.2 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + tiny-glob@0.2.9: dependencies: globalyzer: 0.1.0 @@ -2570,10 +3157,16 @@ snapshots: dependencies: os-tmpdir: 1.0.2 + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + totalist@3.0.1: {} tr46@0.0.3: {} + ts-interface-checker@0.1.13: {} + tslib@1.14.1: {} tslib@2.0.1: {} @@ -2590,6 +3183,12 @@ snapshots: universalify@2.0.1: {} + update-browserslist-db@1.1.1(browserslist@4.24.2): + dependencies: + browserslist: 4.24.2 + escalade: 3.2.0 + picocolors: 1.1.1 + util-deprecate@1.0.2: {} util@0.12.5: @@ -2603,7 +3202,7 @@ snapshots: vite@5.4.10(@types/node@22.9.0): dependencies: esbuild: 0.21.5 - postcss: 8.4.47 + postcss: 8.4.49 rollup: 4.24.3 optionalDependencies: '@types/node': 22.9.0 @@ -2875,6 +3474,8 @@ snapshots: ws@8.18.0: {} + yaml@2.6.1: {} + zimmerframe@1.1.2: {} zod@3.23.8: {} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/src/lib/wizard/components/Configuration.svelte b/src/lib/wizard/components/Configuration.svelte new file mode 100644 index 0000000..dde46f8 --- /dev/null +++ b/src/lib/wizard/components/Configuration.svelte @@ -0,0 +1,53 @@ + + +
+
+
+ + +
+ +
+ + + + + + +
diff --git a/src/lib/wizard/components/Configure.svelte b/src/lib/wizard/components/Configure.svelte deleted file mode 100644 index e9eb6b9..0000000 --- a/src/lib/wizard/components/Configure.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - -

- Contract to compile: {getMainContractName(wizardState.sources)} - - -

diff --git a/src/lib/wizard/components/Network.svelte b/src/lib/wizard/components/Network.svelte new file mode 100644 index 0000000..7ef1db9 --- /dev/null +++ b/src/lib/wizard/components/Network.svelte @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/src/lib/wizard/components/shared/Dropdown.svelte b/src/lib/wizard/components/shared/Dropdown.svelte new file mode 100644 index 0000000..aad5e0a --- /dev/null +++ b/src/lib/wizard/components/shared/Dropdown.svelte @@ -0,0 +1,61 @@ + + +
+ +
+ + + diff --git a/src/lib/wizard/state.svelte.ts b/src/lib/wizard/state.svelte.ts index 26de299..cce2541 100644 --- a/src/lib/wizard/state.svelte.ts +++ b/src/lib/wizard/state.svelte.ts @@ -1,5 +1,7 @@ import type { ContractSources } from "../models/solc"; -export const wizardState = $state<{ sources: ContractSources | undefined }>({ +export const wizardState = $state<{ sources: ContractSources | undefined, apiKey: string, apiSecret: string }>({ sources: undefined, + apiKey: '', + apiSecret: '', }); diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 9703914..3775497 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,5 +1,4 @@ - - +
+

+ +

+
+
+ +
+
+

+ +

+
+
+ +
+
+

+ +

+
+
+ Select approval process +
+
+
diff --git a/src/wizard-app.css b/src/wizard-app.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/src/wizard-app.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..13207cc --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,9 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./src/**/*.{html,js,svelte,ts}'], + theme: { + extend: {}, + }, + plugins: [], +} + From 09ae740ec69f5cbf4c89c1e74f028105b40ef09b Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 4 Dec 2024 18:36:37 -0300 Subject: [PATCH 11/34] authenticate + add support to global state --- src/lib/remix/compiler.ts | 2 +- .../remix/components/ApprovalProcess.svelte | 2 +- src/lib/remix/components/Deploy.svelte | 2 +- src/lib/remix/components/Network.svelte | 2 +- src/lib/remix/components/Setup.svelte | 2 +- src/lib/{remix => }/state/state.svelte.ts | 0 .../wizard/components/Configuration.svelte | 67 ++++++++++++++++--- src/lib/wizard/components/Network.svelte | 59 ++++++++++++---- .../wizard/components/shared/Dropdown.svelte | 18 +++-- src/lib/wizard/state.svelte.ts | 7 -- src/routes/remix.svelte | 2 +- 11 files changed, 123 insertions(+), 40 deletions(-) rename src/lib/{remix => }/state/state.svelte.ts (100%) delete mode 100644 src/lib/wizard/state.svelte.ts diff --git a/src/lib/remix/compiler.ts b/src/lib/remix/compiler.ts index efeff24..ab3233d 100644 --- a/src/lib/remix/compiler.ts +++ b/src/lib/remix/compiler.ts @@ -1,4 +1,4 @@ -import { globalState } from "$lib/remix/state/state.svelte"; +import { globalState } from "$lib/state/state.svelte"; import type { PluginClient } from "@remixproject/plugin" import type { CompilationFileSources, CompilationResult, lastCompilationResult } from "@remixproject/plugin-api"; diff --git a/src/lib/remix/components/ApprovalProcess.svelte b/src/lib/remix/components/ApprovalProcess.svelte index 4c3e836..7edc6fd 100644 --- a/src/lib/remix/components/ApprovalProcess.svelte +++ b/src/lib/remix/components/ApprovalProcess.svelte @@ -1,5 +1,5 @@ @@ -44,10 +76,25 @@
- + - + + + + + {#if successMessage} +
{successMessage}
+ {/if} - + {#if errorMessage} +
{errorMessage}
+ {/if} diff --git a/src/lib/wizard/components/Network.svelte b/src/lib/wizard/components/Network.svelte index 7ef1db9..845eb78 100644 --- a/src/lib/wizard/components/Network.svelte +++ b/src/lib/wizard/components/Network.svelte @@ -1,19 +1,54 @@ - \ No newline at end of file + on:select={(e) => onNetworkSelect(e.detail)} + defaultItem={globalState.form.network ? networkToDropdownItem(globalState.form.network) : undefined} +/> diff --git a/src/lib/wizard/components/shared/Dropdown.svelte b/src/lib/wizard/components/shared/Dropdown.svelte index aad5e0a..a0a6891 100644 --- a/src/lib/wizard/components/shared/Dropdown.svelte +++ b/src/lib/wizard/components/shared/Dropdown.svelte @@ -35,15 +35,23 @@
diff --git a/src/lib/wizard/state.svelte.ts b/src/lib/wizard/state.svelte.ts deleted file mode 100644 index cce2541..0000000 --- a/src/lib/wizard/state.svelte.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ContractSources } from "../models/solc"; - -export const wizardState = $state<{ sources: ContractSources | undefined, apiKey: string, apiSecret: string }>({ - sources: undefined, - apiKey: '', - apiSecret: '', -}); diff --git a/src/routes/remix.svelte b/src/routes/remix.svelte index 6e704fc..74996e5 100644 --- a/src/routes/remix.svelte +++ b/src/routes/remix.svelte @@ -1,7 +1,7 @@ + +
+ onRadioChange(e)} + checked + /> + + + {#key globalState.form.approvalProcessSelected} + onSelectApprovalProcess(e.detail)} + disabled={radioSelected !== "existing"} + defaultItem={globalState.form.approvalProcessSelected + ? { + label: toDisplayName(globalState.form.approvalProcessSelected), + value: globalState.form.approvalProcessSelected, + } + : undefined} + emptyLabel="No Approval Processes Available" + /> + {/key} +
+
+ onRadioChange(e)} + disabled={disableCreation} + title={disableCreation ? "Deploy Environment already exists" : undefined} + /> + + + onSelectApprovalProcessType(e.detail)} + disabled={radioSelected !== "new" || disableCreation} + defaultItem={{ + label: approvalProcessType, + value: approvalProcessType, + }} + /> + + {#if approvalProcessType === "EOA" || approvalProcessType === "Safe"} + + + {:else if approvalProcessType === "Relayer"} + {#if disableRelayers} +
+ +

+ API Key not allowed to manage Relayers +

+
+ {:else} + + onSelectRelayer(e.detail)} + disabled={radioSelected !== "new" || disableCreation} + /> + {/if} + {/if} +
+
+ onRadioChange(e)} + title={disableCreation ? "Deploy Environment already exists" : undefined} + disabled={disableCreation} + /> + +
diff --git a/src/lib/wizard/components/Configuration.svelte b/src/lib/wizard/components/Configuration.svelte index 23a3709..b722866 100644 --- a/src/lib/wizard/components/Configuration.svelte +++ b/src/lib/wizard/components/Configuration.svelte @@ -21,10 +21,11 @@ let loading = $state(false); let successMessage = $state(undefined); let errorMessage = $state(undefined); - let apiKey = ""; - let apiSecret = ""; + let apiKey = $state(""); + let apiSecret = $state(""); function handleGetApiKey() { + // TODO: Implement } async function authenticate() { diff --git a/src/lib/wizard/index.ts b/src/lib/wizard/index.ts index dcac451..78d5b6b 100644 --- a/src/lib/wizard/index.ts +++ b/src/lib/wizard/index.ts @@ -1,5 +1,5 @@ import type { ContractSources } from "../models/solc"; -import { wizardState } from "./state.svelte"; +import { globalState } from "$lib/state/state.svelte"; export interface DefenderDeployMessage { kind: 'oz-wizard-defender-deploy'; @@ -14,7 +14,7 @@ export const initWizardPlugin = () => { function listenToContracts() { window.addEventListener('message', function (e: MessageEvent) { if (e.data.kind === 'oz-wizard-defender-deploy') { - wizardState.sources = e.data.sources; + globalState.contract = { source: e.data.sources } ; } }); } diff --git a/src/routes/wizard.svelte b/src/routes/wizard.svelte index 500c278..fb78965 100644 --- a/src/routes/wizard.svelte +++ b/src/routes/wizard.svelte @@ -5,6 +5,8 @@ import { onMount } from "svelte"; import Configuration from "$lib/wizard/components/Configuration.svelte"; import Network from "$lib/wizard/components/Network.svelte"; + import { wait } from "$lib/utils/helpers"; + import ApprovalProcess from "$lib/wizard/components/ApprovalProcess.svelte"; let currentStep = $state(0); function toggleStep(step: number) { @@ -34,7 +36,7 @@
- + {}} />

@@ -45,7 +47,7 @@

- Select approval process +
From bbaf2a810bf3d02b3e4626564c64d696356f017c Mon Sep 17 00:00:00 2001 From: Marcos Date: Fri, 6 Dec 2024 13:10:50 -0300 Subject: [PATCH 13/34] extract contract name from sources --- src/lib/wizard/components/Configuration.svelte | 6 ------ src/lib/wizard/index.ts | 11 ++++++++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/lib/wizard/components/Configuration.svelte b/src/lib/wizard/components/Configuration.svelte index b722866..81fcd04 100644 --- a/src/lib/wizard/components/Configuration.svelte +++ b/src/lib/wizard/components/Configuration.svelte @@ -12,12 +12,6 @@ // compilationResult = await API.compile(buildCompilerInput(wizardState.sources)); // } - // function getMainContractName(sources?: ContractSources) { - // if (!sources) return ''; - // // The first name that is not a dependency - // return Object.keys(sources).find(name => !name.startsWith('@')); - // } - let loading = $state(false); let successMessage = $state(undefined); let errorMessage = $state(undefined); diff --git a/src/lib/wizard/index.ts b/src/lib/wizard/index.ts index 78d5b6b..5600865 100644 --- a/src/lib/wizard/index.ts +++ b/src/lib/wizard/index.ts @@ -14,7 +14,16 @@ export const initWizardPlugin = () => { function listenToContracts() { window.addEventListener('message', function (e: MessageEvent) { if (e.data.kind === 'oz-wizard-defender-deploy') { - globalState.contract = { source: e.data.sources } ; + globalState.contract = { + source: e.data.sources, + target: getMainContractName(e.data.sources) + } ; } }); } + +function getMainContractName(sources?: ContractSources) { + if (!sources) return ''; + // The first name that is not a dependency + return Object.keys(sources).find(name => !name.startsWith('@')); +} From e3ecae1828021b4e4129b73269eb4b1583f4da74 Mon Sep 17 00:00:00 2001 From: Marcos Date: Fri, 6 Dec 2024 15:11:14 -0300 Subject: [PATCH 14/34] update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a080e66..32b84d4 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ OpenZeppelin Logo

-# Deploy with Defender - Remix Plugin +# Defender Deploy Plugin -Remix plugin to deploy smart contracts using OpenZeppelin Defender. For documentation about usage please visit the [Defender Docs](https://docs.openzeppelin.com/defender/remix-plugin). +Plugin to deploy smart contracts using OpenZeppelin Defender. For documentation about usage in Remix please visit the [Defender Docs](https://docs.openzeppelin.com/defender/remix-plugin). ## Getting Started @@ -16,7 +16,7 @@ pnpm install pnpm dev ``` -The interface is ugly, but don't worry! it's not meant to be used directly, it's used embedded in a Remix iframe instead, and adopts its styles. +The interface is ugly, but don't worry! it's not meant to be used directly, it's used embedded in an iframe instead, and adopts the parent styles. ## Testing in Remix From 24211f8e0a3100e14c0dbb9221a3e78e1d193fa5 Mon Sep 17 00:00:00 2001 From: Marcos Date: Fri, 6 Dec 2024 15:50:02 -0300 Subject: [PATCH 15/34] extract some components + add deploy button at the top level component --- .../wizard/components/ApprovalProcess.svelte | 14 +--- .../wizard/components/Configuration.svelte | 32 ++----- .../wizard/components/shared/Button.svelte | 17 ++++ src/lib/wizard/components/shared/Input.svelte | 14 ++++ src/routes/wizard.svelte | 84 ++++++++++++------- 5 files changed, 97 insertions(+), 64 deletions(-) create mode 100644 src/lib/wizard/components/shared/Button.svelte create mode 100644 src/lib/wizard/components/shared/Input.svelte diff --git a/src/lib/wizard/components/ApprovalProcess.svelte b/src/lib/wizard/components/ApprovalProcess.svelte index eaa273d..3d1e2e6 100644 --- a/src/lib/wizard/components/ApprovalProcess.svelte +++ b/src/lib/wizard/components/ApprovalProcess.svelte @@ -6,6 +6,9 @@ import type { DropdownItem, GlobalState } from "$lib/models/ui"; import type { Relayer } from "$lib/models/relayer"; import { getNetworkLiteral } from "$lib/models/network"; + import Input from "./shared/Input.svelte"; + + let address = $state(""); function approvalProcessByNetworkAndComponent(ap: ApprovalProcess) { const networkName = typeof globalState.form.network === 'string' @@ -159,16 +162,7 @@ /> {#if approvalProcessType === "EOA" || approvalProcessType === "Safe"} - - + {:else if approvalProcessType === "Relayer"} {#if disableRelayers}
diff --git a/src/lib/wizard/components/Configuration.svelte b/src/lib/wizard/components/Configuration.svelte index 81fcd04..023f381 100644 --- a/src/lib/wizard/components/Configuration.svelte +++ b/src/lib/wizard/components/Configuration.svelte @@ -3,14 +3,8 @@ import type { AuthenticationResponse } from "$lib/models/auth"; import type { APIResponse } from "$lib/models/ui"; import { globalState } from "$lib/state/state.svelte"; - - // import { buildCompilerInput, type ContractSources } from "$lib/models/solc"; - // let compilationResult: any; - - // async function compile() { - // if (!wizardState.sources) return; - // compilationResult = await API.compile(buildCompilerInput(wizardState.sources)); - // } + import Button from "./shared/Button.svelte"; + import Input from "./shared/Input.svelte"; let loading = $state(false); let successMessage = $state(undefined); @@ -24,9 +18,9 @@ async function authenticate() { - loading = true; + loading = true; - const result: APIResponse = await API.authenticate({ apiKey, apiSecret }); + const result: APIResponse = await API.authenticate({ apiKey, apiSecret }); if (result.success) { globalState.authenticated = true; @@ -71,19 +65,11 @@ loading = false;
- - - - - - + + + + + \ No newline at end of file diff --git a/src/lib/wizard/components/shared/Input.svelte b/src/lib/wizard/components/shared/Input.svelte new file mode 100644 index 0000000..47cd051 --- /dev/null +++ b/src/lib/wizard/components/shared/Input.svelte @@ -0,0 +1,14 @@ + + +{#if label} + +{/if} + diff --git a/src/routes/wizard.svelte b/src/routes/wizard.svelte index fb78965..28fa0d5 100644 --- a/src/routes/wizard.svelte +++ b/src/routes/wizard.svelte @@ -5,8 +5,25 @@ import { onMount } from "svelte"; import Configuration from "$lib/wizard/components/Configuration.svelte"; import Network from "$lib/wizard/components/Network.svelte"; - import { wait } from "$lib/utils/helpers"; - import ApprovalProcess from "$lib/wizard/components/ApprovalProcess.svelte"; + import { wait } from "$lib/utils/helpers"; + import ApprovalProcess from "$lib/wizard/components/ApprovalProcess.svelte"; + import Button from "$lib/wizard/components/shared/Button.svelte"; + + let deploying = $state(false); + + // import { buildCompilerInput, type ContractSources } from "$lib/models/solc"; + // let compilationResult: any; + + // async function compile() { + // if (!wizardState.sources) return; + // compilationResult = await API.compile(buildCompilerInput(wizardState.sources)); + // } + + const deploy = async () => { + deploying = true; + await wait(2000); + deploying = false; + }; let currentStep = $state(0); function toggleStep(step: number) { @@ -16,38 +33,43 @@ onMount(initWizardPlugin); +
-

- -

-
-
- +
+

+ +

+
+
+ +
-
-

- -

-
-
- {}} /> +

+ +

+
+
+ {}} /> +
-
-

- -

-
-
- +

+ +

+
+
+ +
+
+
From 45a05b264ff108e6dbb9fd8c21c8508b60dd89d5 Mon Sep 17 00:00:00 2001 From: Marcos Date: Fri, 6 Dec 2024 16:26:16 -0300 Subject: [PATCH 16/34] reduce elements size --- .../wizard/components/ApprovalProcess.svelte | 13 ++++--- .../wizard/components/Configuration.svelte | 2 +- .../wizard/components/shared/Dropdown.svelte | 2 +- src/lib/wizard/components/shared/Input.svelte | 7 ++-- src/routes/wizard.svelte | 38 +++++++++---------- 5 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/lib/wizard/components/ApprovalProcess.svelte b/src/lib/wizard/components/ApprovalProcess.svelte index 3d1e2e6..e0af2f9 100644 --- a/src/lib/wizard/components/ApprovalProcess.svelte +++ b/src/lib/wizard/components/ApprovalProcess.svelte @@ -107,7 +107,7 @@ onclick={(e) => onRadioChange(e)} checked /> -
- @@ -63,9 +96,15 @@
+ {#if compilationResult} + {JSON.stringify(compilationResult, null, 2)} + {/if}
+
From eff7e9265aa44bad3f1b0105cc39794043ad35fc Mon Sep 17 00:00:00 2001 From: Marcos Date: Mon, 9 Dec 2024 13:35:51 -0300 Subject: [PATCH 18/34] implement deploy with existing approval process --- src/lib/models/solc.ts | 8 ++++++ src/routes/deploy/+server.ts | 3 +- src/routes/wizard.svelte | 53 ++++++++++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/lib/models/solc.ts b/src/lib/models/solc.ts index 3f635e2..995e23c 100644 --- a/src/lib/models/solc.ts +++ b/src/lib/models/solc.ts @@ -14,6 +14,10 @@ export type CompilerInput = { */ settings: { outputSelection: Record>; + optimizer?: { + enabled: boolean, + runs: number, + }, }; }; @@ -26,6 +30,10 @@ export function buildCompilerInput(sources: ContractSources): CompilerInput { sources, language: 'Solidity', settings: { + optimizer: { + enabled: true, + runs: 200, + }, outputSelection: { '*': { '*': ['*'] } } diff --git a/src/routes/deploy/+server.ts b/src/routes/deploy/+server.ts index 28029c7..0f4b36c 100644 --- a/src/routes/deploy/+server.ts +++ b/src/routes/deploy/+server.ts @@ -10,7 +10,8 @@ export async function POST({ request }: { request: Request }) { const [deploymentResult, error] = await attempt(() => deployContract(credentials, deployment)); if (error) { - return json({ success: false, error: error.msg }); + const internalError = error.errorObject?.response?.data?.message; + return json({ success: false, error: internalError || error.msg }); } return json({ success: true, data: { deployment: deploymentResult } }); diff --git a/src/routes/wizard.svelte b/src/routes/wizard.svelte index cfdbd22..3b9f7dc 100644 --- a/src/routes/wizard.svelte +++ b/src/routes/wizard.svelte @@ -11,11 +11,22 @@ import { API } from "$lib/api"; import { buildCompilerInput, type ContractSources } from "$lib/models/solc"; import Message from "$lib/wizard/components/shared/Message.svelte"; + import type { Artifact, DeployContractRequest } from "$lib/models/deploy"; + import { getNetworkLiteral } from "$lib/models/network"; let busy = $state(false); let successMessage = $state(""); let errorMessage = $state(""); - let compilationResult = $state(); + let compilationResult = $state<{ output: Artifact['output'] }>(); + + let deploymentArtifact = $derived.by(() => { + if (!compilationResult || !globalState.contract?.target || !globalState.contract.source?.sources) return; + + return { + input: buildCompilerInput(globalState.contract.source?.sources as ContractSources), + output: compilationResult.output + } + }); let currentStep = $state(0); function toggleStep(step: number) { @@ -53,7 +64,45 @@ const deploy = async () => { - // TODO: Implement deploy + if (!globalState.form.network) { + displayMessage("No network selected", "error"); + return; + } + + if (!globalState.form.approvalProcessSelected) { + displayMessage("No approval process selected", "error"); + return; + } + + if (!globalState.contract?.target || !globalState.contract.source?.sources) { + displayMessage("No contract selected", "error"); + return; + } + + if (!deploymentArtifact) { + displayMessage("No artifact found", "error"); + return; + } + + const deployRequest: DeployContractRequest = { + artifactPayload: JSON.stringify(deploymentArtifact), + network: getNetworkLiteral(globalState.form.network), + // TODO: Implement approval process creation + approvalProcessId: globalState.form.approvalProcessSelected.approvalProcessId, + contractName: globalState.contract!.target, + contractPath: globalState.contract!.target, + verifySourceCode: true, + // TODO: Implement constructor arguments + constructorBytecode: '', + } + + const res = await API.createDeployment(deployRequest); + if (!res.success) { + displayMessage(`Deployment failed: ${res.error}`, "error"); + return; + } + + displayMessage("Deployment successful", "success"); }; async function compileAndDeploy() { From b7dd07e9aac1e352ef06f315f4b19654f05c5887 Mon Sep 17 00:00:00 2001 From: Marcos Date: Mon, 9 Dec 2024 16:34:12 -0300 Subject: [PATCH 19/34] add deployment logic --- src/lib/remix/components/Deploy.svelte | 2 +- src/lib/utils/contracts.ts | 4 +- .../wizard/components/ApprovalProcess.svelte | 4 +- src/lib/wizard/components/shared/Input.svelte | 6 +- src/routes/wizard.svelte | 225 ++++++++++++++++-- 5 files changed, 217 insertions(+), 24 deletions(-) diff --git a/src/lib/remix/components/Deploy.svelte b/src/lib/remix/components/Deploy.svelte index 105c405..639c7f4 100644 --- a/src/lib/remix/components/Deploy.svelte +++ b/src/lib/remix/components/Deploy.svelte @@ -81,7 +81,7 @@ contractBytecode = getContractBytecode( contractInfo.path, contractInfo.name, - globalState.contract.data + globalState.contract.data.contracts ); } }); diff --git a/src/lib/utils/contracts.ts b/src/lib/utils/contracts.ts index 7882d88..821ba38 100644 --- a/src/lib/utils/contracts.ts +++ b/src/lib/utils/contracts.ts @@ -67,7 +67,7 @@ export function createArtifactPayload( export function getContractBytecode( path: string, contractName: string, - compilation: CompilationResult + contractSources: Record ): string { - return compilation.contracts[path][contractName].evm.bytecode.object; + return contractSources[path][contractName].evm.bytecode.object; } diff --git a/src/lib/wizard/components/ApprovalProcess.svelte b/src/lib/wizard/components/ApprovalProcess.svelte index 5a52e38..5450f97 100644 --- a/src/lib/wizard/components/ApprovalProcess.svelte +++ b/src/lib/wizard/components/ApprovalProcess.svelte @@ -8,7 +8,7 @@ import { getNetworkLiteral } from "$lib/models/network"; import Input from "./shared/Input.svelte"; - let address = $state(""); + let address = $state(globalState.form.approvalProcessToCreate?.via || ""); function approvalProcessByNetworkAndComponent(ap: ApprovalProcess) { const networkName = typeof globalState.form.network === 'string' @@ -163,7 +163,7 @@ {#if approvalProcessType === "EOA" || approvalProcessType === "Safe"}
- +
{:else if approvalProcessType === "Relayer"} {#if disableRelayers} diff --git a/src/lib/wizard/components/shared/Input.svelte b/src/lib/wizard/components/shared/Input.svelte index e40466d..d0e72b6 100644 --- a/src/lib/wizard/components/shared/Input.svelte +++ b/src/lib/wizard/components/shared/Input.svelte @@ -1,12 +1,15 @@ @@ -19,5 +22,6 @@ 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" /> diff --git a/src/routes/wizard.svelte b/src/routes/wizard.svelte index 3b9f7dc..02794fe 100644 --- a/src/routes/wizard.svelte +++ b/src/routes/wizard.svelte @@ -5,20 +5,33 @@ import { onMount } from "svelte"; import Configuration from "$lib/wizard/components/Configuration.svelte"; import Network from "$lib/wizard/components/Network.svelte"; - import ApprovalProcess from "$lib/wizard/components/ApprovalProcess.svelte"; import Button from "$lib/wizard/components/shared/Button.svelte"; - import { globalState } from "$lib/state/state.svelte"; + import { addAPToDropdown, globalState } from "$lib/state/state.svelte"; import { API } from "$lib/api"; import { buildCompilerInput, type ContractSources } from "$lib/models/solc"; import Message from "$lib/wizard/components/shared/Message.svelte"; - import type { Artifact, DeployContractRequest } from "$lib/models/deploy"; + import type { Artifact, DeployContractRequest, UpdateDeploymentRequest } from "$lib/models/deploy"; import { getNetworkLiteral } from "$lib/models/network"; + import { attempt } from "$lib/utils/attempt"; + import { getContractBytecode } from "$lib/utils/contracts"; + import { deployContract, switchToNetwork } from "$lib/ethereum"; + import type { ApprovalProcess as ApprovalProcessType, CreateApprovalProcessRequest } from "$lib/models/approval-process"; + import type { APIResponse } from "$lib/models/ui"; + import { isDeploymentEnvironment, isSameNetwork } from "$lib/utils/helpers"; + import ApprovalProcess from "$lib/wizard/components/ApprovalProcess.svelte"; + + interface DeploymentResult { + deploymentId?: string; + address: string; + hash: string; + sender?: string; + } let busy = $state(false); let successMessage = $state(""); let errorMessage = $state(""); let compilationResult = $state<{ output: Artifact['output'] }>(); - + let deploymentId = $state(undefined); let deploymentArtifact = $derived.by(() => { if (!compilationResult || !globalState.contract?.target || !globalState.contract.source?.sources) return; @@ -28,6 +41,21 @@ } }); + let contractBytecode = $derived.by(() => { + if (!globalState.contract?.target || !compilationResult) return; + + const name = globalState.contract.target; + const sources = compilationResult.output.contracts; + + return getContractBytecode(name, name, sources); + }); + + let constructorBytecode = $derived.by(() => { + return "0x"; + }); + + let deploymentResult = $state(undefined); + let currentStep = $state(0); function toggleStep(step: number) { currentStep = step; @@ -62,15 +90,130 @@ compilationResult = res.data; } + export async function handleInjectedProviderDeployment(bytecode: string) { + // Switch network if needed + const [, networkError] = await attempt(async () => switchToNetwork(globalState.form.network!)); + if (networkError) { + throw new Error(`Error switching network: ${networkError.msg}`); + } + + const [result, error] = await attempt(async () => deployContract(bytecode)); + if (error) { + throw new Error(`Error deploying contract: ${error.msg}`); + } + + if (!result) { + throw new Error("Deployment result not found"); + } + + displayMessage(`Contract deployed successfully, hash: ${result?.hash}`, "success"); + + return { + address: result.address, + hash: result.hash, + sender: result.sender + }; + } + + function findDeploymentEnvironment(via?: string, network?: string) { + if (!via || !network) return undefined; + return globalState.approvalProcesses.find((ap) => + ap.network && + isDeploymentEnvironment(ap) && + isSameNetwork(ap.network, network) && + ap.via?.toLocaleLowerCase() === via.toLocaleLowerCase() + ); + } + + + async function getOrCreateApprovalProcess(): Promise { + const ap = globalState.form.approvalProcessToCreate; + if (!ap || !ap.via || !ap.viaType) { + displayMessage("Must select an approval process to create", "error"); + return; + } - const deploy = async () => { if (!globalState.form.network) { - displayMessage("No network selected", "error"); + displayMessage("Must select a network", "error"); return; } - if (!globalState.form.approvalProcessSelected) { - displayMessage("No approval process selected", "error"); + const existing = findDeploymentEnvironment(ap.via, ap.network); + if (existing) { + return existing; + } + + const apRequest: CreateApprovalProcessRequest = { + name: `Deploy From Remix - ${ap.viaType}`, + via: ap.via, + viaType: ap.viaType, + network: getNetworkLiteral(globalState.form.network), + relayerId: ap.relayerId, + component: ["deploy"], + }; + const result: APIResponse<{ approvalProcess: ApprovalProcessType }> = + await API.createApprovalProcess(apRequest); + + if (!result.success) { + displayMessage(`Approval process creation failed, error: ${JSON.stringify(result.error)}`, "error"); + return; + } + + displayMessage("Deployment Environment successfully created", "success"); + if (!result.data) return; + + addAPToDropdown(result.data.approvalProcess) + return result.data.approvalProcess; + } + + export async function createDefenderDeployment(request: DeployContractRequest) { + const result: APIResponse<{ deployment: { deploymentId: string } }> = + await API.createDeployment(request); + + if (!result.success || !result.data) { + throw new Error(`Contract deployment creation failed: ${JSON.stringify(result.error)}`); + } + + return result.data.deployment.deploymentId; + } + + export async function updateDeploymentStatus( + deploymentId: string, + address: string, + hash: string + ) { + const updateRequest: UpdateDeploymentRequest = { + deploymentId, + hash, + address, + }; + + const result = await API.updateDeployment(updateRequest); + if (!result.success) { + throw new Error(`Failed to update deployment status: ${JSON.stringify(result.error)}`); + } + } + + // function listenForDeployment(deploymentId: string) { + // // polls the deployment status every 10 seconds + // const interval = 10000; + // timeout = setInterval(async () => { + // const result: APIResponse<{ address: string, hash: string }> = await API.getDeployment(deploymentId); + // if (result.success && result.data?.address) { + // deploymentResult = { + // address: result.data.address, + // hash: result.data.hash, + // }; + // logDeploymentResult(deploymentResult); + // clearInterval(timeout); + // } + // }, interval); + // } + + + const deploy = async () => { + if (!globalState.form.network) { + displayMessage("No network selected", "error"); return; } @@ -84,24 +227,73 @@ return; } + // contract deployment requires contract bytecode + // and constructor bytecode to be concatenated. + const bytecode = contractBytecode + constructorBytecode?.slice(2); + + const shouldUseInjectedProvider = globalState.form.approvalType === "injected"; + if (shouldUseInjectedProvider) { + const [result, error] = await attempt(async () => + handleInjectedProviderDeployment(bytecode), + ); + if (error) { + displayMessage(`Error deploying contract: ${error.msg}`, "error"); + return; + } + + deploymentResult = result; + + // loads global state with EOA approval process to create + globalState.form.approvalProcessToCreate = { + viaType: "EOA", + via: deploymentResult?.sender, + network: getNetworkLiteral(globalState.form.network), + }; + globalState.form.approvalProcessSelected = undefined; + } + + const approvalProcess = globalState.form.approvalProcessSelected ?? await getOrCreateApprovalProcess(); + if (!approvalProcess) { + displayMessage("No Approval Process selected", "error"); + return; + }; + const deployRequest: DeployContractRequest = { - artifactPayload: JSON.stringify(deploymentArtifact), network: getNetworkLiteral(globalState.form.network), - // TODO: Implement approval process creation - approvalProcessId: globalState.form.approvalProcessSelected.approvalProcessId, + approvalProcessId: approvalProcess.approvalProcessId, contractName: globalState.contract!.target, contractPath: globalState.contract!.target, verifySourceCode: true, - // TODO: Implement constructor arguments + licenseType: 'MIT', + artifactPayload: JSON.stringify(deploymentArtifact), + // TODO: Implement constructor arguments + salt constructorBytecode: '', + salt: '', } - const res = await API.createDeployment(deployRequest); - if (!res.success) { - displayMessage(`Deployment failed: ${res.error}`, "error"); + const [newDeploymentId, deployError] = await attempt(async () => createDefenderDeployment(deployRequest)); + if (deployError || !newDeploymentId) { + displayMessage(`Deployment failed to create: ${deployError?.msg}`, "error"); return; } + if (shouldUseInjectedProvider && deploymentResult) { + const [, updateError] = await attempt(async () => updateDeploymentStatus( + newDeploymentId, + deploymentResult!.address, + deploymentResult!.hash + )); + if (updateError) { + displayMessage(`Error updating deployment status: ${updateError.msg}`, "error"); + return; + } + } else { + // If we're not using an injected provider + // we need to listen for the deployment to be finished. + // listenForDeployment(newDeploymentId); + } + + deploymentId = newDeploymentId; displayMessage("Deployment successful", "success"); }; @@ -145,9 +337,6 @@ - {#if compilationResult} - {JSON.stringify(compilationResult, null, 2)} - {/if}
@@ -320,7 +320,7 @@
@@ -329,7 +329,7 @@
@@ -346,3 +346,14 @@ {/if}
+ \ No newline at end of file From b84125fd38ef3ae55ffb45bd1c559e16cac5f23e Mon Sep 17 00:00:00 2001 From: Marcos Date: Tue, 10 Dec 2024 09:26:51 -0300 Subject: [PATCH 21/34] 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 24/34] 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}
@@ -65,7 +65,7 @@ class:cursor-not-allowed={!globalState.authenticated} class:text-gray-300={!globalState.authenticated} > - Deploy +

Deploy

@@ -76,13 +76,13 @@
\ No newline at end of file From 05573a7c4503b1d018ceb26a96c0ba62c69d429e Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 11 Dec 2024 15:35:54 -0300 Subject: [PATCH 28/34] update readme --- README.md | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 32b84d4..68139f1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,10 @@ # Defender Deploy Plugin -Plugin to deploy smart contracts using OpenZeppelin Defender. For documentation about usage in Remix please visit the [Defender Docs](https://docs.openzeppelin.com/defender/remix-plugin). +Plugin to deploy smart contracts using OpenZeppelin Defender. Currently supported in: + +- [Remix IDE](https://remix.ethereum.org/) - As a plugin listed in plugins directory, for more information please visit [our docs](https://docs.openzeppelin.com/defender/remix-plugin). +- [Contracts Wizard](https://wizard.openzeppelin.com/) - Integrated in code editor, for more information please visit [our docs](https://docs.openzeppelin.com/defender/remix-plugin). ## Getting Started @@ -16,7 +19,7 @@ pnpm install pnpm dev ``` -The interface is ugly, but don't worry! it's not meant to be used directly, it's used embedded in an iframe instead, and adopts the parent styles. +NOTE: This project is meant to be embedded in other UIs, just running the project won't be enough to see and debug it. You must embed the UI on an external iframe. ## Testing in Remix @@ -31,4 +34,38 @@ Url: http://localhost:5173 # or live version https://defeder-remix-deploy.netlif Type of connection: Iframe Location in Remix: Side Panel ``` -5. You should see the plugin added to the sidebar (new icon with ? symbol). \ No newline at end of file +5. You should see the plugin added to the sidebar (new icon with ? symbol). + +## Testing in Contracts Wizard + +For testing in Contracts Wizard, you must also run the Contracts Wizard UI locally to point to your local plugin. + +1. Run Contracts Wizard locally. + a. Go to (https://github.com/OpenZeppelin/contracts-wizard)[Contracts Wizard Repo]. + b. Clone the latest `master` branch and follow steps to setup the project. + c. Move to `pacakges/ui` and run it with `yarn dev`. +2. In another terminal, run this project using `pnpm dev`, make sure the app is served in `http://localhost:5173`. +3. Open Contracts Wizard local UI, generally in `http://localhost:8080`. +4. Click on "Deploy with Defender" button, you should be able to see embedded the local plugin. + +## Development + +Many parts of codebase are shared across plugins (server side code, state definition, ethereum interactions, etc.), but UI components have a separated implementation to make them more flexible and prevent side-effects. + +We have some bootstrap logic to expose one UI or another depending on the parent iframe domain. + +### Remix +The entrypoint for Remix plugin is `src/routes/remix.svelte`. Its components mainly use [bootstrap](https://getbootstrap.com/) for styling, Remix UI injects bootstrap dependency as a html tag when embedded. + +### Wizard +The entrypoint for Contracts Wizard plugin is `src/routes/wizard.svelte`. Its components mainly use [tailwind CSS](https://tailwindcss.com/) for styling, this is mainly for convenience, since Contracts Wizard was made using this CSS framework. + +## Release + +The repo has a CI/CD connected to our netlify account, when we merge `main` to some of the release branches, a new version of the plugin is released to live. Branches: + +- Remix IDE Plugin - `release-remix` +- Contracts Wizard Plugin - `release-wizard` + +> [!WARNING] +> We use `main` branch as the single source of truth and it's the only branch allowed to be merged to release branches. It should be tested carefully before triggering a new release. \ No newline at end of file From 27780bfa2d097445a3985831467677222a25098b Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 11 Dec 2024 15:40:33 -0300 Subject: [PATCH 29/34] fix list sub items --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 68139f1..e66809d 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,9 @@ Location in Remix: Side Panel For testing in Contracts Wizard, you must also run the Contracts Wizard UI locally to point to your local plugin. 1. Run Contracts Wizard locally. - a. Go to (https://github.com/OpenZeppelin/contracts-wizard)[Contracts Wizard Repo]. - b. Clone the latest `master` branch and follow steps to setup the project. - c. Move to `pacakges/ui` and run it with `yarn dev`. + - a. Go to (https://github.com/OpenZeppelin/contracts-wizard)[Contracts Wizard Repo]. + - b. Clone the latest `master` branch and follow steps to setup the project. + - c. Move to `pacakges/ui` and run it with `yarn dev`. 2. In another terminal, run this project using `pnpm dev`, make sure the app is served in `http://localhost:5173`. 3. Open Contracts Wizard local UI, generally in `http://localhost:8080`. 4. Click on "Deploy with Defender" button, you should be able to see embedded the local plugin. From 854b8a01ccbe3d8c827024a526550528e1e2682d Mon Sep 17 00:00:00 2001 From: Marcos Carlomagno Date: Wed, 11 Dec 2024 21:21:20 -0300 Subject: [PATCH 30/34] Update README.md Co-authored-by: Eric Lau --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e66809d..dad5efa 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Location in Remix: Side Panel For testing in Contracts Wizard, you must also run the Contracts Wizard UI locally to point to your local plugin. 1. Run Contracts Wizard locally. - - a. Go to (https://github.com/OpenZeppelin/contracts-wizard)[Contracts Wizard Repo]. + - a. Go to [https://github.com/OpenZeppelin/contracts-wizard](Contracts Wizard Repo). - b. Clone the latest `master` branch and follow steps to setup the project. - c. Move to `pacakges/ui` and run it with `yarn dev`. 2. In another terminal, run this project using `pnpm dev`, make sure the app is served in `http://localhost:5173`. From 01535fbe80e7723eb397893cfcf97a5d161db065 Mon Sep 17 00:00:00 2001 From: Marcos Date: Thu, 12 Dec 2024 10:49:49 -0300 Subject: [PATCH 31/34] fix prevent adding salt when deterministic is un checked --- src/lib/remix/components/Deploy.svelte | 2 +- src/lib/wizard/components/Deploy.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/remix/components/Deploy.svelte b/src/lib/remix/components/Deploy.svelte index 639c7f4..ea2a4b4 100644 --- a/src/lib/remix/components/Deploy.svelte +++ b/src/lib/remix/components/Deploy.svelte @@ -293,7 +293,7 @@ verifySourceCode: true, artifactPayload, constructorBytecode, - salt, + salt: isDeterministic || enforceDeterministic ? salt : undefined, }; const [newDeploymentId, deployError] = await attempt(async () => createDefenderDeployment(deployRequest)); if (deployError) { diff --git a/src/lib/wizard/components/Deploy.svelte b/src/lib/wizard/components/Deploy.svelte index 1ee82c1..2a8d12d 100644 --- a/src/lib/wizard/components/Deploy.svelte +++ b/src/lib/wizard/components/Deploy.svelte @@ -272,7 +272,7 @@ licenseType: 'MIT', artifactPayload: JSON.stringify(deploymentArtifact), constructorBytecode, - salt, + salt: isDeterministic || enforceDeterministic ? salt : undefined, } const [newDeploymentId, deployError] = await attempt(async () => createDefenderDeployment(deployRequest)); From d43665fd69e78cf36eeb193b131bbc9f094af08a Mon Sep 17 00:00:00 2001 From: Marcos Date: Thu, 12 Dec 2024 12:01:48 -0300 Subject: [PATCH 32/34] react to all types of assets and contract name changed --- src/lib/models/deploy.ts | 10 +++++++ src/lib/wizard/components/Deploy.svelte | 35 ++++++++++++------------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/lib/models/deploy.ts b/src/lib/models/deploy.ts index c1e1296..ce0e2b2 100644 --- a/src/lib/models/deploy.ts +++ b/src/lib/models/deploy.ts @@ -78,3 +78,13 @@ export interface DeploymentResult { hash: string; sender?: string; } + +export type ABITypeParameter = 'uint' | 'uint[]' | 'int' | 'int[]' | 'address' | 'address[]' | 'bool' | 'bool[]' | 'fixed' | 'fixed[]' | 'ufixed' | 'ufixed[]' | 'bytes' | 'bytes[]' | 'function' | 'function[]' | 'tuple' | 'tuple[]' | string; +export interface ABIParameter { + /** The name of the parameter */ + name: string; + /** The canonical type of the parameter */ + type: ABITypeParameter; + /** Used for tuple types */ + components?: ABIParameter[]; +} \ No newline at end of file diff --git a/src/lib/wizard/components/Deploy.svelte b/src/lib/wizard/components/Deploy.svelte index 1ee82c1..dd212e8 100644 --- a/src/lib/wizard/components/Deploy.svelte +++ b/src/lib/wizard/components/Deploy.svelte @@ -2,7 +2,7 @@ import { API } from "$lib/api"; import { deployContract, switchToNetwork } from "$lib/ethereum"; import type { ApprovalProcess, CreateApprovalProcessRequest } from "$lib/models/approval-process"; - import type { Artifact, DeployContractRequest, DeploymentResult, UpdateDeploymentRequest } from "$lib/models/deploy"; + import type { ABIParameter, Artifact, DeployContractRequest, DeploymentResult, UpdateDeploymentRequest } from "$lib/models/deploy"; import { getNetworkLiteral, isProductionNetwork } from "$lib/models/network"; import { buildCompilerInput, type ContractSources } from "$lib/models/solc"; import type { APIResponse } from "$lib/models/ui"; @@ -43,11 +43,6 @@ } }); - let inputs = $derived.by(() => { - if (!compilationResult) return []; - return getConstructorInputsWizard(globalState.contract?.target, compilationResult.output.contracts); - }); - let displayUpgradeableWarning = $derived.by(() => { return isUpgradeable(globalState.contract?.source?.sources as ContractSources); }); @@ -66,6 +61,9 @@ : undefined ); + + let inputs: ABIParameter[] = $state([]); + $effect(() => { if (globalState.contract?.source?.sources) { compile(); @@ -92,6 +90,10 @@ return; } compilationResult = res.data; + + if (globalState.contract?.target && compilationResult) { + inputs = getConstructorInputsWizard(globalState.contract.target, compilationResult.output.contracts); + } } function displayMessage(message: string, type: "success" | "error") { @@ -266,8 +268,8 @@ const deployRequest: DeployContractRequest = { network: getNetworkLiteral(globalState.form.network), approvalProcessId: approvalProcess.approvalProcessId, - contractName: globalState.contract!.target, - contractPath: globalState.contract!.target, + contractName: globalState.contract.target, + contractPath: globalState.contract.target, verifySourceCode: true, licenseType: 'MIT', artifactPayload: JSON.stringify(deploymentArtifact), @@ -310,19 +312,18 @@
- {#if displayUpgradeableWarning} {/if} {#if inputs.length > 0} -
Constructor Arguments
- {#each inputs as input} - - {/each} -{:else} - -{/if} +
Constructor Arguments
+ {#each inputs as input} + + {/each} + {:else} + + {/if}
{/if} - - {#if currentTab === index} -
+
{#if index === 0} wait(1000).then(() => toggle(1))}/>{/if} {#if index === 1} wait(1000).then(() => toggle(2))}/>{/if}