diff --git a/.gitignore b/.gitignore index fd3dbb5..a14154f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ # misc .DS_Store +.vscode/ *.pem # debug diff --git a/components/build-deploy-panel.tsx b/components/build-deploy-panel.tsx index 9509f7d..99691d2 100644 --- a/components/build-deploy-panel.tsx +++ b/components/build-deploy-panel.tsx @@ -6,13 +6,15 @@ import { useCliCommands } from "./workspace/use-cli-commands"; import useSWR, { mutate } from "swr"; import { db } from "@/data/db"; import { useWorkspaceId } from "./workspace/use-workspace-id"; -import { Download, Rocket, ShieldCheck, Wrench, TestTube2, Link2 } from "lucide-react"; +import { Download, Rocket, ShieldCheck, Wrench, TestTube2, Link2, HandCoins } from "lucide-react"; import UploadModal from "./workspace/upload-modal"; import { Tooltip } from "./tooltip"; +import { AuditType } from "@/data/audit"; export function BuildDeployPanel() { const commands = useCliCommands(); const [isAuditing, setIsAuditing] = useState(false); + const [isSaveGasFeeAuditing, setIsSaveGasFeeAuditing] = useState(false); const [isBuilding, setIsBuilding] = useState(false); const [isDeploying, setIsDeploying] = useState(false); const [isTesting, setIsTesting] = useState(false); @@ -38,7 +40,7 @@ export function BuildDeployPanel() { onClick: async () => { setIsAuditing(true); try { - await commands.audit(); + await commands.audit(AuditType.DEFAULT); } catch (err) { console.log(err); } finally { @@ -47,6 +49,21 @@ export function BuildDeployPanel() { }, icon: ShieldCheck, }, + { + disabled: isSaveGasFeeAuditing, + title: "Save Gas Fee", + onClick: async () => { + setIsSaveGasFeeAuditing(true); + try { + await commands.audit(AuditType.SAVE_GAS_FEE); + } catch (err) { + console.log(err); + } finally { + setIsSaveGasFeeAuditing(false); + } + }, + icon: HandCoins, + }, { disabled: isBuilding, title: "Build", diff --git a/components/file-explorer/index.tsx b/components/file-explorer/index.tsx index 44c7d23..780544e 100644 --- a/components/file-explorer/index.tsx +++ b/components/file-explorer/index.tsx @@ -94,7 +94,7 @@ const FileExplorer = () => { }); if (children.length === 0) { - setSearchParams("file", encodeURIComponent(id)); + setSearchParams({ file: encodeURIComponent(id) }); } }} // @ts-expect-error diff --git a/components/workspace/use-cli-commands.tsx b/components/workspace/use-cli-commands.tsx index 84d7f65..e98f67f 100644 --- a/components/workspace/use-cli-commands.tsx +++ b/components/workspace/use-cli-commands.tsx @@ -7,7 +7,12 @@ import { usePathname } from "next/navigation"; import { PropsWithChildren, useContext, useEffect, useState } from "react"; import { TerminalContext } from "react-terminal"; import { useWorkspaceId } from "./use-workspace-id"; -import { uploadContractCode, useAudit, useAuditReport } from "@/data/audit"; +import { + AuditType, + uploadContractCode, + useAudit, + useAuditReport, +} from "@/data/audit"; import clsx from "clsx"; import { fileContentToZip } from "@/lib/file-content-to-zip"; import { saveAs } from "file-saver"; @@ -36,7 +41,9 @@ export function useCliCommands() {
  • test - tests the current workspace
  • deploy - deploys the built smart contract
  • export - exports the current workspace
  • -
  • share - generates a share link for the current workspace
  • +
  • + share - generates a share link for the current workspace +
  • check txID - checks the result of transaction
  • @@ -44,7 +51,7 @@ export function useCliCommands() { ); }, - audit: async () => { + audit: async (auditType: AuditType) => { const start = `${pathname}/`; terminalContext.setBufferedContent( <> @@ -70,7 +77,7 @@ export function useCliCommands() { ); try { - const codeHash = await uploadContractCode(files); + const codeHash = await uploadContractCode(auditType, files); terminalContext.setBufferedContent( <> @@ -80,13 +87,17 @@ export function useCliCommands() { if (!wallet) return; - setSearchParams("auditId", codeHash); + setSearchParams({ auditId: codeHash, auditType }); const { TransactionId } = await wallet.auditTransfer(codeHash); terminalContext.setBufferedContent( <> - + ); } catch (err) { @@ -258,7 +269,9 @@ export function useCliCommands() { const file = new File( [zip], `${pathname?.split("/")?.pop() || "export"}.zip`, - { type: "data:application/octet-stream;base64," } + { + type: "data:application/octet-stream;base64,", + } ); saveAs(file); }, @@ -281,7 +294,8 @@ export function useCliCommands() { <>

    Loaded files: {files.map((i) => i.path).join(", ")}

    - Generating share link... + Generating share + link...

    ); @@ -293,9 +307,7 @@ export function useCliCommands() { }); const { id } = await res.json(); - terminalContext.setBufferedContent( - - ); + terminalContext.setBufferedContent(); } catch (err) { if (err instanceof Error) terminalContext.setBufferedContent(<>{err.message}); @@ -385,21 +397,29 @@ function DeployedContractDetails({ id }: { id?: string }) { } function AuditReport({ + auditType, codeHash, transactionId, }: { + auditType: AuditType; codeHash: string; transactionId: string; }) { - const { isLoading, error } = useAudit(codeHash, transactionId); + const { isLoading, error } = useAudit(auditType, codeHash, transactionId); if (isLoading || !!error) return Loading report...; - return ; + return ; } -function AuditReportResult({ codeHash }: { codeHash: string }) { - const { data, isLoading } = useAuditReport(codeHash); +function AuditReportResult({ + auditType, + codeHash, +}: { + auditType: AuditType; + codeHash: string; +}) { + const { data, isLoading } = useAuditReport(auditType, codeHash); if (isLoading || !data) return Loading report...; @@ -438,4 +458,3 @@ function AuditReportResult({ codeHash }: { codeHash: string }) { ); } - diff --git a/data/audit.ts b/data/audit.ts index fc03e89..7d08bd4 100644 --- a/data/audit.ts +++ b/data/audit.ts @@ -7,9 +7,30 @@ import { fileContentToZip } from "@/lib/file-content-to-zip"; import { v4 as uuidv4 } from "uuid"; import { useSearchParams } from "next/navigation"; +export enum AuditType { + DEFAULT = "default", + SAVE_GAS_FEE = "saveGasFee", +} + +const URL_CONFIG = { + [AuditType.DEFAULT]: { + uploadContractCode: "/api/playground/audit/uploadContractCode", + auditContractCode: "/api/playground/audit/auditContractCode", + report: "/api/playground/report", + }, + [AuditType.SAVE_GAS_FEE]: { + uploadContractCode: "/api/playground/adjustGasFee/uploadContractCode", + auditContractCode: "/api/playground/adjustGasFee/execute", + report: "/api/playground/adjustGasFee/report", + }, +}; + const uploadContractCodeSchema = z.object({ codeHash: z.string() }); -export async function uploadContractCode(files: FileContent[]) { +export async function uploadContractCode( + auditType: AuditType, + files: FileContent[] +) { const zippedData = fileContentToZip(files); const formData = new FormData(); @@ -27,7 +48,7 @@ export async function uploadContractCode(files: FileContent[]) { }; const res = await fetch( - `/api/playground/audit/uploadContractCode`, + URL_CONFIG[auditType].uploadContractCode, requestInit ); @@ -46,12 +67,16 @@ export async function uploadContractCode(files: FileContent[]) { const auditSchema = z.object({ reportUrl: z.string() }); -export function useAudit(auditId?: string, transactionId?: string) { +export function useAudit( + auditType: AuditType, + auditId?: string, + transactionId?: string +) { return useSWRImmutable( auditId && transactionId ? `audit-${auditId}-${transactionId}` : undefined, async () => { const res = await fetch( - `/api/playground/audit/auditContractCode?auditId=${auditId}&transactionId=${transactionId}` + `${URL_CONFIG[auditType].auditContractCode}?auditId=${auditId}&transactionId=${transactionId}` ); const data = await res.json(); @@ -75,11 +100,13 @@ const auditReportSchema = z.record( ) ); -export function useAuditReport(auditId?: string) { +export function useAuditReport(auditType?: AuditType, auditId?: string) { return useSWRImmutable( auditId ? `audit-report-${auditId}` : undefined, async () => { - const res = await fetch(`/api/playground/report/${auditId}`); + if (!auditType) return; + + const res = await fetch(`${URL_CONFIG[auditType].report}/${auditId}`); const data = await res.json(); @@ -94,5 +121,6 @@ export function useAuditReport(auditId?: string) { export function useAuditReportSearchParam() { const params = useSearchParams(); const auditId = params.get("auditId"); - return useAuditReport(auditId || undefined); -} \ No newline at end of file + const auditType = params.get("auditType") as AuditType | null; + return useAuditReport(auditType || undefined, auditId || undefined); +} diff --git a/lib/set-search-params.ts b/lib/set-search-params.ts index 239f4a1..a70bc1f 100644 --- a/lib/set-search-params.ts +++ b/lib/set-search-params.ts @@ -9,11 +9,16 @@ export function useSetSearchParams() { const router = useRouter(); const createQueryString = useCallback( - (key: string, value?: string) => { + (paramsObj: Record) => { const params = new URLSearchParams(searchParams.toString()); - params.delete(key); - if (value) params.set(key, value); + Object.keys(paramsObj).forEach((key) => { + params.delete(key); + const value = paramsObj[key]; + if (value) { + params.set(key, value); + } + }); const res = params.toString(); @@ -24,7 +29,7 @@ export function useSetSearchParams() { [searchParams] ); - return (key: string, value?: string) => { - router.push(pathname + createQueryString(key, value)); + return (paramsObj: Record) => { + router.push(pathname + createQueryString(paramsObj)); }; } diff --git a/next.config.mjs b/next.config.mjs index e80071f..efbdc6f 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -38,6 +38,10 @@ if (process.env.NODE_ENV === "development") { source: "/api/playground/report/:path*", destination: `https://playground-next.test.aelf.dev/api/playground/report/:path*`, }, + { + source: "/api/playground/adjustGasFee/:path*", + destination: `https://playground-next.test.aelf.dev/api/playground/adjustGasFee/:path*`, + }, ]; }; }