Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release to wizard #13

Merged
merged 11 commits into from
Dec 4, 2024
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
57 changes: 57 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
11 changes: 11 additions & 0 deletions src/lib/api.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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();
35 changes: 35 additions & 0 deletions src/lib/models/solc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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: ContractSources;
/**
* Settings for the compiler.
* e.g. { outputSelection: { '*': { '*': ['*'] } }"
*/
settings: {
outputSelection: Record<string, Record<string, string[]>>;
};
};

export type ContractSources = {
[source: string]: { content: string };
};

export function buildCompilerInput(sources: ContractSources): CompilerInput {
return {
sources,
language: 'Solidity',
settings: {
outputSelection: {
'*': { '*': ['*'] }
}
}
};
}

27 changes: 27 additions & 0 deletions src/lib/wizard/components/Configure.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script lang="ts">
import { API } from "$lib/api";
import { buildCompilerInput, type ContractSources } from "$lib/models/solc";
import { wizardState } from "../state.svelte";

let compilationResult: any;

async function compile() {
if (!wizardState.sources) return;
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('@'));
}

</script>

<p>
Contract to compile: {getMainContractName(wizardState.sources)}

<button onclick={compile} >
Compile
</button>
</p>
18 changes: 17 additions & 1 deletion src/lib/wizard/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
import type { ContractSources } from "../models/solc";
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.
// listenToContracts();
listenToContracts();
}

function listenToContracts() {
window.addEventListener('message', function (e: MessageEvent<DefenderDeployMessage>) {
if (e.data.kind === 'oz-wizard-defender-deploy') {
wizardState.sources = e.data.sources;
}
});
}
5 changes: 5 additions & 0 deletions src/lib/wizard/state.svelte.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { ContractSources } from "../models/solc";

export const wizardState = $state<{ sources: ContractSources | undefined }>({
sources: undefined,
});
15 changes: 6 additions & 9 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}

});
</script>

Expand Down
19 changes: 19 additions & 0 deletions src/routes/compiler/+server.ts
Original file line number Diff line number Diff line change
@@ -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 } });
}
20 changes: 20 additions & 0 deletions src/routes/compiler/compiler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import solc from 'solc';

import type { ContractSources } from "$lib/models/solc";
import type { CompilerInput } from "$lib/models/solc";

export class SolidityCompiler {
getContent(path: string, contents: ContractSources) {
if (contents[path]) {
return contents[path];
}
return { error: 'File not found' };
}

compile(input: CompilerInput, contents?: ContractSources) {
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;
}
}
4 changes: 4 additions & 0 deletions src/routes/remix.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script lang="ts">
import { onMount } from "svelte";
import { initRemixPlugin } from "$lib/remix";
import { globalState } from "$lib/remix/state/state.svelte";
import Setup from "$lib/remix/components/Setup.svelte";
import Network from "$lib/remix/components/Network.svelte";
Expand Down Expand Up @@ -48,6 +50,8 @@

return false;
});

onMount(initRemixPlugin);
</script>

<p>
Expand Down
8 changes: 7 additions & 1 deletion src/routes/wizard.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
<script lang="ts">
import { initWizardPlugin } from "$lib/wizard";
import { onMount } from "svelte";
import Configure from "$lib/wizard/components/Configure.svelte";

onMount(initWizardPlugin);
</script>

<p>Defender Deploy in Wizard</p>
<Configure />

Loading