From d51456abcbf975d876839ab97635ee8e39baab5c Mon Sep 17 00:00:00 2001 From: ci-bot Date: Mon, 8 Sep 2025 14:49:37 +0100 Subject: [PATCH 01/15] Add plumbing for template explorer to modal plugin --- .../src/app/plugins/notification.tsx | 9 ++++- .../app/src/lib/remix-app/actions/modals.ts | 4 ++- .../app/src/lib/remix-app/context/context.tsx | 4 ++- .../src/lib/remix-app/context/provider.tsx | 36 +++++++++++++++++-- .../app/src/lib/remix-app/interface/index.ts | 35 ++++++++++++++++++ 5 files changed, 83 insertions(+), 5 deletions(-) diff --git a/apps/remix-ide/src/app/plugins/notification.tsx b/apps/remix-ide/src/app/plugins/notification.tsx index 2d0455a31de..009e5bd9b9b 100644 --- a/apps/remix-ide/src/app/plugins/notification.tsx +++ b/apps/remix-ide/src/app/plugins/notification.tsx @@ -1,8 +1,10 @@ +/* eslint-disable @nrwl/nx/enforce-module-boundaries */ import { Plugin } from '@remixproject/engine' import { LibraryProfile, MethodApi, StatusEvents } from '@remixproject/plugin-utils' import { AppModal } from '@remix-ui/app' import { AlertModal } from '@remix-ui/app' import { dispatchModalInterface } from '@remix-ui/app' +import { TemplateExplorerModal } from 'libs/remix-ui/app/src/lib/remix-app/interface' interface INotificationApi { events: StatusEvents @@ -10,6 +12,7 @@ interface INotificationApi { modal: (args: AppModal) => void alert: (args: AlertModal) => void toast: (message: string) => void + templateExplorer: (args: TemplateExplorerModal) => void } } @@ -17,7 +20,7 @@ const profile: LibraryProfile = { name: 'notification', displayName: 'Notification', description: 'Displays notifications', - methods: ['modal', 'alert', 'toast'] + methods: ['modal', 'alert', 'toast', 'templateExplorer'] } export class NotificationPlugin extends Plugin implements MethodApi { @@ -34,6 +37,10 @@ export class NotificationPlugin extends Plugin implements MethodApi = { [Key in keyof M]: M[Key] extends undefined @@ -13,6 +13,7 @@ type ActionMap = { export const enum modalActionTypes { setModal = 'SET_MODAL', + setTemplateExplorer = 'SET_TEMPLATE_EXPLORER', setToast = 'SET_TOAST', processQueue = 'PROCESS_QUEUEU', handleHideModal = 'HANDLE_HIDE_MODAL', @@ -21,6 +22,7 @@ export const enum modalActionTypes { type ModalPayload = { [modalActionTypes.setModal]: AppModal + [modalActionTypes.setTemplateExplorer]: TemplateExplorerModal [modalActionTypes.handleHideModal]: any [modalActionTypes.setToast]: { message: string | JSX.Element, timestamp: number } [modalActionTypes.handleToaster]: any, diff --git a/libs/remix-ui/app/src/lib/remix-app/context/context.tsx b/libs/remix-ui/app/src/lib/remix-app/context/context.tsx index 48aa1b391e1..3acadcdd688 100644 --- a/libs/remix-ui/app/src/lib/remix-app/context/context.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/context/context.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { AlertModal, AppModal, AppState } from '../interface' +import { AlertModal, AppModal, AppState, TemplateExplorerModal } from '../interface' import { ModalInitialState } from '../state/modals' import { AppAction } from '../actions/app' @@ -26,6 +26,7 @@ export interface dispatchModalInterface { modal: (data: AppModal) => void toast: (message: string | JSX.Element) => void alert: (data: AlertModal) => void + templateExplorer: (data: TemplateExplorerModal) => void handleHideModal: () => void handleToaster: () => void } @@ -34,6 +35,7 @@ export const dispatchModalContext = React.createContext( modal: (data: AppModal) => {}, toast: (message: string | JSX.Element) => {}, alert: (data: AlertModal) => {}, + templateExplorer: (data: TemplateExplorerModal) => {}, handleHideModal: () => {}, handleToaster: () => {} }) diff --git a/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx index baa7931ce85..3f766c1ee5a 100644 --- a/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx @@ -1,7 +1,7 @@ import React, { useReducer } from 'react' import { useIntl, IntlShape } from 'react-intl' import { modalActionTypes } from '../actions/modals' -import { AlertModal, AppModal } from '../interface' +import { AlertModal, AppModal, TemplateExplorerModal } from '../interface' import { modalReducer } from '../reducer/modals' import { ModalInitialState } from '../state/modals' import { ModalTypes } from '../types' @@ -51,6 +51,38 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt }) } + const templateExplorer = (modalData: TemplateExplorerModal) => { + dispatch({ + type: modalActionTypes.setTemplateExplorer, + payload: { + id: modalData.id, + title: modalData.title, + message: modalData.message, + okLabel: modalData.okLabel, + okFn: modalData.okFn, + cancelLabel: modalData.cancelLabel, + cancelFn: modalData.cancelFn, + timestamp: modalData.timestamp, + hide: modalData.hide, + validationFn: modalData.validationFn, + resolve: modalData.resolve, + next: modalData.next, + data: modalData.data, + showCancelIcon: modalData.showCancelIcon, + preventBlur: modalData.preventBlur, + placeholderText: modalData.placeholderText, + workspaceTemplateGroup: modalData.workspaceTemplateGroup, + workspaceTemplate: modalData.workspaceTemplate, + workspaceTemplateOptions: modalData.workspaceTemplateOptions, + workspaceName: modalData.workspaceName, + modifyWorkspaceName: modalData.modifyWorkspaceName, + workspaceDescription: modalData.workspaceDescription, + workspaceTags: modalData.workspaceTags, + modifyWorkspace: modalData.modifyWorkspace + } + }) + } + const alert = (modalData: AlertModal) => { return modal({ id: modalData.id, @@ -85,7 +117,7 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt } return ( - + {children} ) diff --git a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts index 084795e3212..98d1667fe06 100644 --- a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts +++ b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts @@ -1,5 +1,7 @@ +/* eslint-disable @nrwl/nx/enforce-module-boundaries */ import { branch, desktopConnection, GitHubUser } from '@remix-api' import { AppModalCancelTypes, ModalTypes } from '../types' +import { Template, TemplateGroup, TemplateOption } from 'libs/remix-ui/workspace/src/lib/utils/constants' export type ValidationResult = { valid: boolean, @@ -49,6 +51,39 @@ export interface forceChoiceModal { message: string | JSX.Element, } +export interface TemplateExplorerModal { + id: string + title?: string, + message: JSX.Element, + workspaceName: string, + modifyWorkspaceName: boolean, + workspaceDescription: string, + workspaceTemplateOptions: TemplateOption, + workspaceTemplateGroup: TemplateGroup, + workspaceTemplate: Template, + timestamp?: number + hide?: boolean + validationFn?: (value: string) => ValidationResult + // eslint-disable-next-line no-undef + okLabel: string | JSX.Element + okFn?: (value?:any) => void + cancelLabel?: string | JSX.Element + cancelFn?: (reason?: AppModalCancelTypes) => void, + modalType?: ModalTypes, + modalParentClass?: string + defaultValue?: string + hideFn?: () => void, + resolve?: (value?:any) => void, + next?: () => void, + data?: any, + showCancelIcon?: boolean, + preventBlur?: boolean + placeholderText?: string + searchTerm?: string + workspaceTags?: string[] + modifyWorkspace?: boolean +} + export interface AppState { gitHubUser: GitHubUser currentBranch: branch From d9af0cfd5dfd54a48e68ec7b7b32cb68da46d51b Mon Sep 17 00:00:00 2001 From: ci-bot Date: Mon, 8 Sep 2025 17:14:07 +0100 Subject: [PATCH 02/15] setup and state changes for template explorer modal --- .../src/app/plugins/notification.tsx | 1 + .../components/modals/dialogViewPlugin.tsx | 4 ++-- .../src/lib/remix-app/context/provider.tsx | 12 ++++++++-- .../app/src/lib/remix-app/interface/index.ts | 1 + .../app/src/lib/remix-app/reducer/modals.ts | 4 ++++ .../app/src/lib/remix-app/state/modals.ts | 24 ++++++++++++++++++- .../home-tab/src/lib/remix-ui-home-tab.tsx | 13 ++++++++++ 7 files changed, 54 insertions(+), 5 deletions(-) diff --git a/apps/remix-ide/src/app/plugins/notification.tsx b/apps/remix-ide/src/app/plugins/notification.tsx index 009e5bd9b9b..4c9feadde46 100644 --- a/apps/remix-ide/src/app/plugins/notification.tsx +++ b/apps/remix-ide/src/app/plugins/notification.tsx @@ -38,6 +38,7 @@ export class NotificationPlugin extends Plugin implements MethodApi { - const { modal, alert, toast } = useDialogDispatchers() + const { modal, alert, toast, templateExplorer } = useDialogDispatchers() const app = useContext(AppContext) useEffect(() => { - app.modal.setDispatcher({ modal, alert, toast }) + app.modal.setDispatcher({ modal, alert, toast, templateExplorer }) }, []) return <> } diff --git a/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx index 3f766c1ee5a..439768de35b 100644 --- a/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx @@ -14,7 +14,7 @@ declare global { } export const ModalProvider = ({ children = [], reducer = modalReducer, initialState = ModalInitialState } = {}) => { - const [{ modals, toasters, focusModal, focusToaster }, dispatch] = useReducer(reducer, initialState) + const [{ modals, toasters, focusModal, focusToaster, focusTemplateExplorer }, dispatch] = useReducer(reducer, initialState) const onNextFn = async () => { dispatch({ @@ -118,7 +118,7 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt return ( - {children} + {children} ) } @@ -141,3 +141,11 @@ export const useDialogs = () => { export const useDialogDispatchers = () => { return React.useContext(dispatchModalContext) } + +export function defaultFocusTemplateExplorer () { + return ( + <> +

Template Explorer

+ + ) +} diff --git a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts index 98d1667fe06..251604da3b7 100644 --- a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts +++ b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts @@ -43,6 +43,7 @@ export interface ModalState { toasters: {message: (string | JSX.Element), timestamp: number }[], focusModal: AppModal, focusToaster: {message: (string | JSX.Element), timestamp: number } + focusTemplateExplorer: TemplateExplorerModal } export interface forceChoiceModal { diff --git a/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts b/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts index 9be604ce80f..4e26a6073af 100644 --- a/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts +++ b/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts @@ -83,5 +83,9 @@ export const modalReducer = (state: ModalState = ModalInitialState, action: Moda return { ...state, toasters: []} } } + + case modalActionTypes.setTemplateExplorer: { + return { ...state, focusTemplateExplorer: action.payload } + } } } diff --git a/libs/remix-ui/app/src/lib/remix-app/state/modals.ts b/libs/remix-ui/app/src/lib/remix-app/state/modals.ts index 56993cc7ec9..cd6135ef0ba 100644 --- a/libs/remix-ui/app/src/lib/remix-app/state/modals.ts +++ b/libs/remix-ui/app/src/lib/remix-app/state/modals.ts @@ -1,4 +1,6 @@ +import { Template, TemplateGroup } from '@remix-ui/workspace' import { ModalState } from '../interface' +import { defaultFocusTemplateExplorer } from '../context/provider' export const ModalInitialState: ModalState = { modals: [], @@ -15,5 +17,25 @@ export const ModalInitialState: ModalState = { cancelFn: () => { }, showCancelIcon: false }, - focusToaster: { message: '', timestamp: 0 } + focusToaster: { message: '', timestamp: 0 }, + focusTemplateExplorer: { + id: '', + hide: true, + title: '', + message: defaultFocusTemplateExplorer(), + validationFn: () => { return { valid: true, message: '' } }, + okLabel: '', + okFn: () => { }, + cancelLabel: '', + cancelFn: () => { }, + showCancelIcon: false, + preventBlur: false, + placeholderText: '', + workspaceName: '', + modifyWorkspaceName: false, + workspaceDescription: '', + workspaceTemplateOptions: {}, + workspaceTemplateGroup: {} as TemplateGroup, + workspaceTemplate: {} as Template, + } } diff --git a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx index 4f47bd6cbd7..c82d98399bb 100644 --- a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx +++ b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx @@ -77,6 +77,18 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => { // return (<>) // } + const openTemplateExplorer = async () => { + console.log('openTemplateExplorer') + await plugin.call('notification', 'templateExplorer', { + id: 'templateExplorer', + title: 'Explore all templates', + message:
Explore all templates
, + okLabel: 'Explore all templates', + okFn: () => {} + }) + _paq.push(['trackEvent', 'hometab', 'header', 'Explore all templates']) + } + return (
@@ -85,6 +97,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
+
From 0f50376651dec5f0b821df2469b2d5138c74b8d8 Mon Sep 17 00:00:00 2001 From: ci-bot Date: Mon, 15 Sep 2025 16:02:49 +0100 Subject: [PATCH 03/15] create template explorer modal. modify app context. --- apps/remix-ide/src/app.ts | 5 + .../src/app/plugins/notification.tsx | 10 +- .../src/app/plugins/remix-generic-modal.tsx | 69 ++ apps/remix-ide/src/app/plugins/remixGuide.tsx | 2 +- .../templates-selection-plugin.tsx | 4 +- apps/remix-ide/src/remixAppManager.ts | 4 +- .../app/src/lib/remix-app/actions/app.ts | 5 +- .../app/src/lib/remix-app/actions/modals.ts | 10 +- .../components/modals/dialogViewPlugin.tsx | 4 +- .../app/src/lib/remix-app/context/context.tsx | 4 +- .../src/lib/remix-app/context/provider.tsx | 43 +- .../app/src/lib/remix-app/interface/index.ts | 27 +- .../app/src/lib/remix-app/reducer/app.ts | 9 +- .../app/src/lib/remix-app/remix-app.tsx | 17 +- .../app/src/lib/remix-app/state/app.ts | 2 +- .../app/src/lib/remix-app/state/modals.ts | 10 +- .../components/environment-explorer-ui.tsx | 2 +- .../reducers/template-explorer-reducer.tsx | 19 + .../src/components/template-explorer-body.tsx | 26 + .../src/components/template-explorer.tsx | 508 ++++++++++++ .../generic-modal/src/components/topCard.tsx | 30 + libs/remix-ui/generic-modal/src/index.ts | 1 + .../src/lib/remix-ui-generic-modal.css | 69 ++ .../src/lib/remix-ui-generic-modal.tsx | 55 ++ .../generic-modal/src/utils/helpers.tsx | 775 ++++++++++++++++++ .../types/template-explorer-types.ts | 17 + .../grid-view/src/lib/remix-ui-grid-cell.tsx | 5 +- .../home-tab/src/lib/remix-ui-home-tab.tsx | 23 +- .../modal-dialog/src/lib/types/index.ts | 1 + libs/remix-ui/workspace/src/index.ts | 1 + .../workspace/src/lib/utils/templates.ts | 429 ++++++++++ 31 files changed, 2089 insertions(+), 97 deletions(-) create mode 100644 apps/remix-ide/src/app/plugins/remix-generic-modal.tsx create mode 100644 libs/remix-ui/generic-modal/reducers/template-explorer-reducer.tsx create mode 100644 libs/remix-ui/generic-modal/src/components/template-explorer-body.tsx create mode 100644 libs/remix-ui/generic-modal/src/components/template-explorer.tsx create mode 100644 libs/remix-ui/generic-modal/src/components/topCard.tsx create mode 100644 libs/remix-ui/generic-modal/src/index.ts create mode 100644 libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.css create mode 100644 libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.tsx create mode 100644 libs/remix-ui/generic-modal/src/utils/helpers.tsx create mode 100644 libs/remix-ui/generic-modal/types/template-explorer-types.ts create mode 100644 libs/remix-ui/workspace/src/lib/utils/templates.ts diff --git a/apps/remix-ide/src/app.ts b/apps/remix-ide/src/app.ts index 6f524ae840e..77f6c478ecf 100644 --- a/apps/remix-ide/src/app.ts +++ b/apps/remix-ide/src/app.ts @@ -111,6 +111,7 @@ import Terminal from './app/panels/terminal' import TabProxy from './app/panels/tab-proxy.js' import { Plugin } from '@remixproject/engine' import BottomBarPanel from './app/components/bottom-bar-panel' +import { TemplateExplorerModalPlugin } from './app/plugins/remix-generic-modal' const _paq = (window._paq = window._paq || []) @@ -157,6 +158,7 @@ class AppComponent { popupPanel: PopupPanel statusBar: StatusBar topBar: Topbar + templateExplorerModal: TemplateExplorerModalPlugin settings: SettingsTab params: any desktopClientMode: boolean @@ -401,6 +403,8 @@ class AppComponent { const templateSelection = new TemplatesSelectionPlugin() + const templateExplorerModal = new TemplateExplorerModalPlugin() + const walletConnect = new WalletConnect() this.engine.register([ @@ -456,6 +460,7 @@ class AppComponent { pluginStateLogger, matomo, templateSelection, + templateExplorerModal, scriptRunnerUI, remixAI, remixAiAssistant, diff --git a/apps/remix-ide/src/app/plugins/notification.tsx b/apps/remix-ide/src/app/plugins/notification.tsx index 4c9feadde46..c37b74d0a61 100644 --- a/apps/remix-ide/src/app/plugins/notification.tsx +++ b/apps/remix-ide/src/app/plugins/notification.tsx @@ -4,7 +4,6 @@ import { LibraryProfile, MethodApi, StatusEvents } from '@remixproject/plugin-ut import { AppModal } from '@remix-ui/app' import { AlertModal } from '@remix-ui/app' import { dispatchModalInterface } from '@remix-ui/app' -import { TemplateExplorerModal } from 'libs/remix-ui/app/src/lib/remix-app/interface' interface INotificationApi { events: StatusEvents @@ -12,7 +11,7 @@ interface INotificationApi { modal: (args: AppModal) => void alert: (args: AlertModal) => void toast: (message: string) => void - templateExplorer: (args: TemplateExplorerModal) => void + } } @@ -20,7 +19,7 @@ const profile: LibraryProfile = { name: 'notification', displayName: 'Notification', description: 'Displays notifications', - methods: ['modal', 'alert', 'toast', 'templateExplorer'] + methods: ['modal', 'alert', 'toast'] } export class NotificationPlugin extends Plugin implements MethodApi { @@ -37,11 +36,6 @@ export class NotificationPlugin extends Plugin implements MethodApi = () => { } + event: any + appStateDispatch: any + constructor() { + super(pluginProfile) + this.element = document.createElement('div') + this.element.setAttribute('id', 'remix-generic-modal') + this.dispatch = () => { } + this.event = new EventEmitter() + } + + async onActivation(): Promise { + + } + + onDeactivation(): void { + this.element.remove() + } + + setDispatch(dispatch: React.Dispatch) { + this.dispatch = dispatch + this.renderComponent() + } + + setAppStateDispatch(appStateDispatch: React.Dispatch) { + this.appStateDispatch = appStateDispatch + } + + render() { + return ( +
+ +
+ ) + } + + renderComponent(): void { + this.dispatch({ + element: this.element, + }) + } + + updateComponent(state: RemixUiGenericModalProps, appState: AppState) { + return ( + + ) + } +} diff --git a/apps/remix-ide/src/app/plugins/remixGuide.tsx b/apps/remix-ide/src/app/plugins/remixGuide.tsx index 39ae0cb59a8..46247594e4a 100644 --- a/apps/remix-ide/src/app/plugins/remixGuide.tsx +++ b/apps/remix-ide/src/app/plugins/remixGuide.tsx @@ -121,7 +121,7 @@ export class RemixGuidePlugin extends ViewPlugin { > { section.cells.map((cell, index) => { return = { [Key in keyof M]: M[Key] extends undefined @@ -18,6 +19,7 @@ export const enum appActionTypes { setCanUseGit = 'SET_CAN_USE_GIT', setShowPopupPanel = 'SET_SHOW_POPUP_PANEL', setConnectedToDesktop = 'SET_CONNECTED_TO_DESKTOP', + showGenericModal = 'SHOW_GENERIC_MODAL', } type AppPayload = { @@ -26,7 +28,8 @@ type AppPayload = { [appActionTypes.setNeedsGitInit]: boolean, [appActionTypes.setCanUseGit]: boolean, [appActionTypes.setShowPopupPanel]: boolean, - [appActionTypes.setConnectedToDesktop]: desktopConnection + [appActionTypes.setConnectedToDesktop]: desktopConnection, + [appActionTypes.showGenericModal]: boolean } export type AppAction = ActionMap[keyof ActionMap< diff --git a/libs/remix-ui/app/src/lib/remix-app/actions/modals.ts b/libs/remix-ui/app/src/lib/remix-app/actions/modals.ts index 14dd00dae38..c4fed0d70e9 100644 --- a/libs/remix-ui/app/src/lib/remix-app/actions/modals.ts +++ b/libs/remix-ui/app/src/lib/remix-app/actions/modals.ts @@ -1,4 +1,4 @@ -import { AppModal, TemplateExplorerModal } from '../interface' +import { AppModal, GenericModal } from '../interface' type ActionMap = { [Key in keyof M]: M[Key] extends undefined @@ -13,20 +13,20 @@ type ActionMap = { export const enum modalActionTypes { setModal = 'SET_MODAL', - setTemplateExplorer = 'SET_TEMPLATE_EXPLORER', setToast = 'SET_TOAST', processQueue = 'PROCESS_QUEUEU', handleHideModal = 'HANDLE_HIDE_MODAL', - handleToaster = 'HANDLE_HIDE_TOAST' + handleToaster = 'HANDLE_HIDE_TOAST', + setTemplateExplorer = 'SET_TEMPLATE_EXPLORER' } type ModalPayload = { [modalActionTypes.setModal]: AppModal - [modalActionTypes.setTemplateExplorer]: TemplateExplorerModal [modalActionTypes.handleHideModal]: any [modalActionTypes.setToast]: { message: string | JSX.Element, timestamp: number } [modalActionTypes.handleToaster]: any, - [modalActionTypes.processQueue]: any + [modalActionTypes.processQueue]: any, + [modalActionTypes.setTemplateExplorer]: GenericModal } export type ModalAction = ActionMap[keyof ActionMap< diff --git a/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx index 03268574bce..d5610de56cd 100644 --- a/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx @@ -3,11 +3,11 @@ import { AppContext } from '../../context/context' import { useDialogDispatchers } from '../../context/provider' const DialogViewPlugin = () => { - const { modal, alert, toast, templateExplorer } = useDialogDispatchers() + const { modal, alert, toast } = useDialogDispatchers() const app = useContext(AppContext) useEffect(() => { - app.modal.setDispatcher({ modal, alert, toast, templateExplorer }) + app.modal.setDispatcher({ modal, alert, toast }) }, []) return <> } diff --git a/libs/remix-ui/app/src/lib/remix-app/context/context.tsx b/libs/remix-ui/app/src/lib/remix-app/context/context.tsx index 3acadcdd688..48aa1b391e1 100644 --- a/libs/remix-ui/app/src/lib/remix-app/context/context.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/context/context.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { AlertModal, AppModal, AppState, TemplateExplorerModal } from '../interface' +import { AlertModal, AppModal, AppState } from '../interface' import { ModalInitialState } from '../state/modals' import { AppAction } from '../actions/app' @@ -26,7 +26,6 @@ export interface dispatchModalInterface { modal: (data: AppModal) => void toast: (message: string | JSX.Element) => void alert: (data: AlertModal) => void - templateExplorer: (data: TemplateExplorerModal) => void handleHideModal: () => void handleToaster: () => void } @@ -35,7 +34,6 @@ export const dispatchModalContext = React.createContext( modal: (data: AppModal) => {}, toast: (message: string | JSX.Element) => {}, alert: (data: AlertModal) => {}, - templateExplorer: (data: TemplateExplorerModal) => {}, handleHideModal: () => {}, handleToaster: () => {} }) diff --git a/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx index 439768de35b..4d68896c30f 100644 --- a/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx @@ -1,12 +1,11 @@ import React, { useReducer } from 'react' import { useIntl, IntlShape } from 'react-intl' import { modalActionTypes } from '../actions/modals' -import { AlertModal, AppModal, TemplateExplorerModal } from '../interface' +import { AlertModal, AppModal } from '../interface' import { modalReducer } from '../reducer/modals' import { ModalInitialState } from '../state/modals' import { ModalTypes } from '../types' import { AppContext, dispatchModalContext, modalContext, platformContext, onLineContext } from './context' - declare global { interface Window { _intl: IntlShape @@ -51,38 +50,6 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt }) } - const templateExplorer = (modalData: TemplateExplorerModal) => { - dispatch({ - type: modalActionTypes.setTemplateExplorer, - payload: { - id: modalData.id, - title: modalData.title, - message: modalData.message, - okLabel: modalData.okLabel, - okFn: modalData.okFn, - cancelLabel: modalData.cancelLabel, - cancelFn: modalData.cancelFn, - timestamp: modalData.timestamp, - hide: modalData.hide, - validationFn: modalData.validationFn, - resolve: modalData.resolve, - next: modalData.next, - data: modalData.data, - showCancelIcon: modalData.showCancelIcon, - preventBlur: modalData.preventBlur, - placeholderText: modalData.placeholderText, - workspaceTemplateGroup: modalData.workspaceTemplateGroup, - workspaceTemplate: modalData.workspaceTemplate, - workspaceTemplateOptions: modalData.workspaceTemplateOptions, - workspaceName: modalData.workspaceName, - modifyWorkspaceName: modalData.modifyWorkspaceName, - workspaceDescription: modalData.workspaceDescription, - workspaceTags: modalData.workspaceTags, - modifyWorkspace: modalData.modifyWorkspace - } - }) - } - const alert = (modalData: AlertModal) => { return modal({ id: modalData.id, @@ -117,8 +84,10 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt } return ( - - {children} + + + {children} + ) } @@ -142,7 +111,7 @@ export const useDialogDispatchers = () => { return React.useContext(dispatchModalContext) } -export function defaultFocusTemplateExplorer () { +export const defaultFocusTemplateExplorer = () => { return ( <>

Template Explorer

diff --git a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts index 251604da3b7..d4d574630b0 100644 --- a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts +++ b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts @@ -42,8 +42,8 @@ export interface ModalState { modals: AppModal[], toasters: {message: (string | JSX.Element), timestamp: number }[], focusModal: AppModal, - focusToaster: {message: (string | JSX.Element), timestamp: number } - focusTemplateExplorer: TemplateExplorerModal + focusToaster: {message: (string | JSX.Element), timestamp: number }, + focusTemplateExplorer: GenericModal } export interface forceChoiceModal { @@ -52,18 +52,27 @@ export interface forceChoiceModal { message: string | JSX.Element, } -export interface TemplateExplorerModal { - id: string - title?: string, - message: JSX.Element, +export interface TemplateExplorerGenericData { workspaceName: string, modifyWorkspaceName: boolean, workspaceDescription: string, workspaceTemplateOptions: TemplateOption, workspaceTemplateGroup: TemplateGroup, workspaceTemplate: Template, + workspaceTags: string[] + searchTerm?: string + modifyWorkspace?: boolean +} + +export interface GenericModal { + id: string + title?: JSX.Element, + message: JSX.Element, + footer?: JSX.Element, + genericData?: any, timestamp?: number hide?: boolean + showModal?: boolean validationFn?: (value: string) => ValidationResult // eslint-disable-next-line no-undef okLabel: string | JSX.Element @@ -80,9 +89,8 @@ export interface TemplateExplorerModal { showCancelIcon?: boolean, preventBlur?: boolean placeholderText?: string - searchTerm?: string - workspaceTags?: string[] - modifyWorkspace?: boolean + width?: string + height?: string } export interface AppState { @@ -93,5 +101,6 @@ export interface AppState { showPopupPanel: boolean connectedToDesktop: desktopConnection desktopClientConnected: desktopConnection + genericModalState?: GenericModal } diff --git a/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts b/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts index 2110a638997..f047fdb2f47 100644 --- a/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts +++ b/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts @@ -42,5 +42,12 @@ export const appReducer = (state: AppState, action: AppAction): AppState => { connectedToDesktop: action.payload } } + + case appActionTypes.showGenericModal: { + return { + ...state, + genericModalState: { ...state.genericModalState, showModal: action.payload } + } + } } -} \ No newline at end of file +} diff --git a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx index 58c87575a24..618e094a0bb 100644 --- a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @nrwl/nx/enforce-module-boundaries */ import React, { useEffect, useReducer, useRef, useState } from 'react' import './style/remix-app.css' import { RemixUIMainPanel } from '@remix-ui/panel' @@ -14,6 +15,7 @@ import { appReducer } from './reducer/app' import { appInitialState } from './state/app' import isElectron from 'is-electron' import { desktopConnectionType } from '@remix-api' +import { RemixUiGenericModal } from 'libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal' declare global { interface Window { @@ -47,7 +49,19 @@ const RemixApp = (props: IRemixAppUi) => { const [appState, appStateDispatch] = useReducer(appReducer, { ...appInitialState, showPopupPanel: !window.localStorage.getItem('did_show_popup_panel') && !isElectron(), - connectedToDesktop: props.app.desktopClientMode ? desktopConnectionType .disconnected : desktopConnectionType .disabled + connectedToDesktop: props.app.desktopClientMode ? desktopConnectionType .disconnected : desktopConnectionType .disabled, + genericModalState: { + id: '', + title:
Default Title
, + message:
Default Message
, + footer:
Default Footer
, + okLabel: 'Default Ok Label', + okFn: () => { }, + cancelLabel: 'Default Cancel Label', + cancelFn: () => { }, + width: '892px', + height: '768px' + } }) useEffect(() => { @@ -218,6 +232,7 @@ const RemixApp = (props: IRemixAppUi) => {
+ {appState.genericModalState.showModal && } diff --git a/libs/remix-ui/app/src/lib/remix-app/state/app.ts b/libs/remix-ui/app/src/lib/remix-app/state/app.ts index 4c0eae622ee..d7b7fc4085b 100644 --- a/libs/remix-ui/app/src/lib/remix-app/state/app.ts +++ b/libs/remix-ui/app/src/lib/remix-app/state/app.ts @@ -9,4 +9,4 @@ export const appInitialState: AppState = { showPopupPanel: false, connectedToDesktop: desktopConnectionType.disabled, desktopClientConnected: desktopConnectionType.disabled -} \ No newline at end of file +} diff --git a/libs/remix-ui/app/src/lib/remix-app/state/modals.ts b/libs/remix-ui/app/src/lib/remix-app/state/modals.ts index cd6135ef0ba..b48186f3091 100644 --- a/libs/remix-ui/app/src/lib/remix-app/state/modals.ts +++ b/libs/remix-ui/app/src/lib/remix-app/state/modals.ts @@ -21,8 +21,9 @@ export const ModalInitialState: ModalState = { focusTemplateExplorer: { id: '', hide: true, - title: '', + title: defaultFocusTemplateExplorer(), message: defaultFocusTemplateExplorer(), + footer: defaultFocusTemplateExplorer(), validationFn: () => { return { valid: true, message: '' } }, okLabel: '', okFn: () => { }, @@ -31,11 +32,6 @@ export const ModalInitialState: ModalState = { showCancelIcon: false, preventBlur: false, placeholderText: '', - workspaceName: '', - modifyWorkspaceName: false, - workspaceDescription: '', - workspaceTemplateOptions: {}, - workspaceTemplateGroup: {} as TemplateGroup, - workspaceTemplate: {} as Template, + genericData: {} } } diff --git a/libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx b/libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx index 138c09b718c..ce2d36a44f4 100644 --- a/libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx +++ b/libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx @@ -96,7 +96,7 @@ export const EnvironmentExplorerUI = (props: environmentExplorerUIProps) => { > {section.providers.map(provider => ( { + switch (action.type) { + case 'SET_TEMPLATE_EXPLORER': + return action.payload + } +} diff --git a/libs/remix-ui/generic-modal/src/components/template-explorer-body.tsx b/libs/remix-ui/generic-modal/src/components/template-explorer-body.tsx new file mode 100644 index 00000000000..dd50506618f --- /dev/null +++ b/libs/remix-ui/generic-modal/src/components/template-explorer-body.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import { TopCard, TopCardProps } from './topCard' +import { TemplateExplorer } from './template-explorer' + +export interface TemplateExplorerBodyProps { + topCards: TopCardProps[] + plugin: any +} + +export function TemplateExplorerBody({ topCards, plugin }: TemplateExplorerBodyProps) { + return ( +
+
+ {/* {props.appState.genericModalState.title && props.appState.genericModalState.title} {props.appState.genericModalState.title} */} +
+ {topCards.map((card) => ( + + ))} +
+
+
+ +
+
+ ) +} diff --git a/libs/remix-ui/generic-modal/src/components/template-explorer.tsx b/libs/remix-ui/generic-modal/src/components/template-explorer.tsx new file mode 100644 index 00000000000..b971473c77e --- /dev/null +++ b/libs/remix-ui/generic-modal/src/components/template-explorer.tsx @@ -0,0 +1,508 @@ +import { CustomTooltip } from '@remix-ui/helper' +import { RemixUIGridCell, RemixUIGridSection, RemixUIGridView } from '@remix-ui/remix-ui-grid-view' +import { templates } from '@remix-ui/workspace' + +import isElectron from 'is-electron' +import React, { useState, useMemo } from 'react' +import { metadata, templatesRepository } from '../utils/helpers' + +export interface TemplateItem { + value: string + displayName?: string + description?: string + tagList?: string[] + IsArtefact?: boolean + opts?: { + upgradeable?: string + mintable?: boolean + burnable?: boolean + pausable?: boolean + } + templateType?: any +} + +export interface TemplateCategory { + name: string + description?: string + hasOptions?: boolean + IsArtefact?: boolean + tooltip?: string + onClick?: () => void + onClickLabel?: string + items: TemplateItem[] +} + +export interface TemplateExplorerProps { + plugin: any +} + +export function TemplateExplorer({ plugin }: TemplateExplorerProps) { + const [selectedTag, setSelectedTag] = useState(null) + const [recentBump, setRecentBump] = useState(0) + + console.log('metadata', metadata) + console.log('templatesRepository', templatesRepository) + + // Get all unique tags from all templates + const allTags = useMemo((): string[] => { + const tags: string[] = [] + + if (templatesRepository && Array.isArray(templatesRepository)) { + templatesRepository.forEach((template: any) => { + if (template && template.items && Array.isArray(template.items)) { + template.items.forEach((item: any) => { + if (item && item.tagList && Array.isArray(item.tagList)) { + item.tagList.forEach((tag: string) => { + if (typeof tag === 'string' && !tags.includes(tag)) { + tags.push(tag) + } + }) + } + }) + } + }) + } + + return tags.sort() + }, []) + + // Recent templates (before filteredTemplates so it can be referenced later) + const recentTemplates = useMemo((): TemplateItem[] => { + try { + const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null + const list: string[] = raw ? JSON.parse(raw) : [] + const items: TemplateItem[] = [] + if (Array.isArray(templatesRepository)) { + list.forEach((val) => { + for (const group of templatesRepository as any[]) { + if (group && Array.isArray(group.items)) { + const found = group.items.find((it: any) => it && it.value === val) + if (found) { + items.push(found) + break + } + } + } + }) + } + //tag filter + const filtered = selectedTag + ? items.filter((it: any) => it && Array.isArray(it.tagList) && it.tagList.includes(selectedTag)) + : items + return filtered + } catch (e) { + return [] + } + }, [selectedTag, recentBump]) + + // Filter templates based on selected tag + const filteredTemplates = useMemo((): TemplateCategory[] => { + if (!selectedTag || !templatesRepository || !Array.isArray(templatesRepository)) { + return templatesRepository as TemplateCategory[] || [] + } + + return (templatesRepository as TemplateCategory[]).map((template: any) => ({ + ...template, + items: template.items.filter((item: any) => + item && item.tagList && Array.isArray(item.tagList) && item.tagList.includes(selectedTag) + ) + })).filter((template: any) => template && template.items && template.items.length > 0) + }, [selectedTag]) + + // Dedupe templates across the whole page and avoid showing ones already in recents + const dedupedTemplates = useMemo((): TemplateCategory[] => { + const recentSet = new Set((recentTemplates || []).map((t: any) => t && t.value)) + const seen = new Set() + const makeUniqueItems = (items: any[]) => { + const unique: any[] = [] + for (const it of items || []) { + const val = it && it.value + if (!val) continue + if (recentSet.has(val)) continue + if (seen.has(val)) continue + seen.add(val) + unique.push(it) + } + return unique + } + return (filteredTemplates || []).map((group: any) => ({ + ...group, + items: makeUniqueItems(group && group.items ? group.items : []) + })).filter((g: any) => g && g.items && g.items.length > 0) + }, [filteredTemplates, recentTemplates]) + + const handleTagClick = (tag: string) => { + setSelectedTag(selectedTag === tag ? null : tag) + } + + const clearFilter = () => { + setSelectedTag(null) + } + + const RECENT_KEY = 'remix.recentTemplates' + + const addRecentTemplate = (templateValue: string) => { + try { + const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null + const list: string[] = raw ? JSON.parse(raw) : [] + const filtered = list.filter((v) => v !== templateValue) + filtered.unshift(templateValue) + const trimmed = filtered.slice(0, 4) + if (typeof window !== 'undefined') window.localStorage.setItem(RECENT_KEY, JSON.stringify(trimmed)) + setRecentBump((v) => v + 1) + } catch (e) { + + } + } + + return ( +
+ {/* Tag Filter Row */} +
+
+ Filter by tag: + + {allTags.map((tag: any) => ( + + ))} + {selectedTag && ( + + + + )} +
+
+ + {/* Recently Used Section */} + {recentTemplates && recentTemplates.length > 0 && ( +
+

+ Recently used +

+
+ {recentTemplates.map((item: TemplateItem, itemIndex) => { + item.templateType = metadata[item.value] + if (item.templateType && item.templateType.disabled === true) return null + if (item.templateType && item.templateType.desktopCompatible === false && isElectron()) return null + return ( +
{ + addRecentTemplate(item.value) + }} + onMouseEnter={(e) => { + e.currentTarget.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)' + e.currentTarget.style.transform = 'translateY(-2px)' + }} + onMouseLeave={(e) => { + e.currentTarget.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)' + e.currentTarget.style.transform = 'translateY(0)' + }} + > +
+
+ {item.displayName || item.value} +
+ {item.tagList && item.tagList.length > 0 && ( +
+ {item.tagList.map((tag, tagIndex) => ( + + {tag} + + ))} +
+ )} +
+
+ {item.description && ( +

+ {item.description} +

+ )} + {item.opts && Object.keys(item.opts).length > 0 && ( +
+ {item.opts.upgradeable && ( + + UUPS + + )} + {item.opts.mintable && ( + + Mint + + )} + {item.opts.burnable && ( + + Burn + + )} + {item.opts.pausable && ( + + Pause + + )} +
+ )} +
+
+ ) + })} +
+
+ )} + + {dedupedTemplates.map((template: TemplateCategory, templateIndex) => ( +
+

+ {template.name} +

+ + {template.description && ( +

+ {template.description} +

+ )} + +
+ {template.items.map((item: TemplateItem, itemIndex) => { + // Add template metadata + item.templateType = metadata[item.value] + + // Skip disabled items + if (item.templateType && item.templateType.disabled === true) return null + + // Skip desktop incompatible items in electron + if (item.templateType && item.templateType.desktopCompatible === false && isElectron()) return null + + return ( +
{ + console.log('Template selected:', item.value, item.opts) + addRecentTemplate(item.value) + }} + onMouseEnter={(e) => { + e.currentTarget.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)' + e.currentTarget.style.transform = 'translateY(-2px)' + }} + onMouseLeave={(e) => { + e.currentTarget.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)' + e.currentTarget.style.transform = 'translateY(0)' + }} + > +
+
+ {item.displayName || item.value} +
+ + {item.tagList && item.tagList.length > 0 && ( +
+ {item.tagList.map((tag, tagIndex) => ( + + {tag} + + ))} +
+ )} +
+ +
+ {item.description && ( +

+ {item.description} +

+ )} + + {item.opts && Object.keys(item.opts).length > 0 && ( +
+ {item.opts.upgradeable && ( + + UUPS + + )} + {item.opts.mintable && ( + + Mint + + )} + {item.opts.burnable && ( + + Burn + + )} + {item.opts.pausable && ( + + Pause + + )} +
+ )} +
+
+ ) + })} +
+ + {/* Special handling for Cookbook section */} + {template.name === 'Cookbook' && ( +
+
+ More from Cookbook +
+

+ {template.description} +

+ +
+ )} +
+ ))} +
+ ) +} diff --git a/libs/remix-ui/generic-modal/src/components/topCard.tsx b/libs/remix-ui/generic-modal/src/components/topCard.tsx new file mode 100644 index 00000000000..d502eb95dba --- /dev/null +++ b/libs/remix-ui/generic-modal/src/components/topCard.tsx @@ -0,0 +1,30 @@ +import React from 'react' + +export interface TopCardProps { + title: string + description: string + icon: string + onClick: () => void + importWorkspace: boolean +} + +export function TopCard(props: TopCardProps) { + + return ( +
+ + {props.title.includes('AI') ? : } + + +

{props.title}

+

{props.description}

+
+
+ ) +} diff --git a/libs/remix-ui/generic-modal/src/index.ts b/libs/remix-ui/generic-modal/src/index.ts new file mode 100644 index 00000000000..2c6c5ec82f7 --- /dev/null +++ b/libs/remix-ui/generic-modal/src/index.ts @@ -0,0 +1 @@ +export * from './lib/remix-ui-generic-modal' diff --git a/libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.css b/libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.css new file mode 100644 index 00000000000..66f627594ce --- /dev/null +++ b/libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.css @@ -0,0 +1,69 @@ +.generic-modal-background { + position: fixed; + display: flex; + justify-content: center; + align-items: center; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: transparent; +} + +.generic-modal-container { + border-radius: 10px; + display: flex; + box-shadow: 0 0 5px 5px rgba(0, 0, 0, 0.1); + flex-direction: column; +} + +.generic-modal-close-container { + display: flex; + justify-content: flex-end; + align-items: center; +} + +.generic-modal-close-button { + background-color: transparent; + border: none; + cursor: pointer; + font-size: 1.5rem; +} + +.hover-cursor { + cursor: pointer; +} + +.hover-cursor:hover { + cursor: pointer; + border: 2px dashed var(--bs-info-border-subtle); +} + +.generic-modal-close-button:hover { + background-color: transparent; +} + +.generic-modal-close-button:focus { + background-color: transparent; +} + +.generic-modal-close-button:active { + background-color: transparent; +} + +.generic-modal-close-button:disabled { + background-color: transparent; +} + +.generic-modal-close-button:focus-visible { + background-color: transparent; +} + +.explora-topcard { + cursor: pointer; +} + +.explora-topcard:hover { + border-color: pink; + cursor: pointer !important; +} diff --git a/libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.tsx b/libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.tsx new file mode 100644 index 00000000000..1f9657a72c3 --- /dev/null +++ b/libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.tsx @@ -0,0 +1,55 @@ +import React from 'react' +import './remix-ui-generic-modal.css' +import { appActionTypes, AppState } from '@remix-ui/app' +import { TopCard, TopCardProps } from '../components/topCard' +import { TemplateExplorerBody } from '../components/template-explorer-body' + +export interface RemixUiGenericModalProps { + dispatch: any + appState: AppState + plugin: any +} + +const topCards: TopCardProps[] = [ + { + title: 'Create blank', + description: 'Create an empty workspace', + icon: 'fa-solid fa-plus', + onClick: () => alert('Create blank'), + importWorkspace: false + }, + { + title: 'Create with AI', + description: 'Generate a workspace with AI', + icon: 'assets/img/remixai-logoDefault.webp', + onClick: () => alert('Create with AI'), + importWorkspace: false + }, + { + title: 'Import Project', + description: 'Import an existing project', + icon: 'fas fa-upload', + onClick: () => alert('Import Project'), + importWorkspace: true + } + +] + +export function RemixUiGenericModal (props: RemixUiGenericModalProps) { + + return ( +
+
+
+ +
+ +
+ {props.appState.genericModalState.footer && props.appState.genericModalState.footer} +
+
+
+ ) +} diff --git a/libs/remix-ui/generic-modal/src/utils/helpers.tsx b/libs/remix-ui/generic-modal/src/utils/helpers.tsx new file mode 100644 index 00000000000..178051b3a16 --- /dev/null +++ b/libs/remix-ui/generic-modal/src/utils/helpers.tsx @@ -0,0 +1,775 @@ +// import { TEMPLATE_METADATA } from "@remix-ui/workspace" + +export const templatesRepository = [ + { + name: "Generic", + items: [ + { value: "remixDefault", tagList: ["Solidity"], + // displayName: intl.formatMessage({ id: 'filePanel.basic' }), + description: 'The default project', + // templateType: TEMPLATE_METADATA['remixDefault'] + }, + { value: "blank", + // displayName: intl.formatMessage({ id: 'filePanel.blank' }), + IsArtefact: true, description: 'A blank project', + // templateType: TEMPLATE_METADATA['blank'] + }, + { value: "simpleEip7702", displayName: 'Simple EIP 7702', IsArtefact: true, description: 'Pectra upgrade allowing externally owned accounts (EOAs) to run contract code.', + // templateType: TEMPLATE_METADATA['simpleEip7702'] + }, + { value: "accountAbstraction", displayName: 'Account Abstraction', IsArtefact: true, description: 'A repo about ERC-4337 and EIP-7702', + // templateType: TEMPLATE_METADATA['accountAbstraction'] + }, + { value: 'remixAiTemplate', tagList: ['AI'], displayName: 'RemixAI Template Generation', IsArtefact: true, description: 'AI generated workspace. Workspace gets generated with a user prompt.', + // templateType: TEMPLATE_METADATA['remixAiTemplate'] + }, + { value: "introToEIP7702", displayName: 'Intro to EIP-7702', IsArtefact: true, description: 'A contract for demoing EIP-7702', + // templateType: TEMPLATE_METADATA['introToEIP7702'] + }, + ] + }, + { + name: "OpenZeppelin", + hasOptions: true, + items: [ + { + value: "ozerc20", + displayName: "ERC20", + tagList: ["ERC20", "Solidity"], + description: 'A customizable fungible token contract', + // templateType: TEMPLATE_METADATA['ozerc20'] + }, + { + value: "ozerc20", + displayName: "ERC20", + description: "An ERC20 contract with:", + tagList: ["Solidity"], + opts: { + mintable: true + }, + // templateType: TEMPLATE_METADATA['ozerc20'] + }, + { + value: "ozerc20", + displayName: "ERC20", + description: "An ERC20 contract with:", + tagList: ["Solidity", "ERC20"], + opts: { + mintable: true, + burnable: true + }, + // templateType: TEMPLATE_METADATA['ozerc20'] + }, + { + value: "ozerc20", + displayName: "ERC20", + description: "An ERC20 contract with:", + opts: { + mintable: true, + pausable: true + }, + tagList: ["ERC20", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc20'] + }, + { + value: "ozerc721", + displayName: "ERC721 (NFT)", + tagList: ["ERC721", "Solidity"], + description: 'A customizable non-fungible token (NFT) contract', + // templateType: TEMPLATE_METADATA['ozerc721'] + }, + { + value: "ozerc721", + displayName: "ERC721 (NFT)", + description: "An ERC721 contract with:", + tagList: ["Solidity", "ERC721"], + opts: { + mintable: true + }, + // templateType: TEMPLATE_METADATA['ozerc721'] + }, + { + value: "ozerc721", + displayName: "ERC721 (NFT)", + description: "An ERC721 contract with:", + opts: { + mintable: true, + burnable: true + }, + tagList: ["ERC721", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc721'] + }, + { + value: "ozerc721", + displayName: "ERC721 (NFT)", + description: "An ERC721 contract with:", + opts: { + mintable: true, + pausable: true + }, + tagList: ["ERC721", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc721'] + }, + { + value: "ozerc1155", + tagList: ["Solidity"], + displayName: "ERC1155", + description: 'A customizable multi token contract', + // templateType: TEMPLATE_METADATA['ozerc1155'] + }, + { + value: "ozerc1155", + displayName: "ERC1155", + tagList: ["Solidity"], + description: "An ERC1155 contract with:", + opts: { + mintable: true + }, + // templateType: TEMPLATE_METADATA['ozerc1155'] + }, + { + value: "ozerc1155", + displayName: "ERC1155", + description: "An ERC1155 contract with:", + opts: { + mintable: true, + burnable: true + }, + tagList: ["ERC1155", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc1155'] + }, + { + value: "ozerc1155", + displayName: "ERC1155", + description: "An ERC1155 contract with:", + tagList: ["ERC1155"], + opts: { + mintable: true, + pausable: true + }, + // templateType: TEMPLATE_METADATA['ozerc1155'] + } + ] + }, + { + name: "OpenZeppelin Proxy", + items: [ + { + value: "ozerc20", + displayName: "UUPS ERC20", + description: "A simple ERC20 contract using the Universal Upgradeable Proxy Standard (UUPS) pattern", + opts: { + upgradeable: 'uups' + }, + tagList: ["ERC20", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc20'] + }, + { + value: "ozerc20", + displayName: "UUPS ERC20", + description: "UUPS ERC20 contract with:", + opts: { + upgradeable: 'uups', + mintable: true + }, + tagList: ["ERC20", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc20'] + }, + { + value: "ozerc20", + displayName: "UUPS ERC20", + description: "UUPS ERC20 contract with:", + opts: { + upgradeable: 'uups', + mintable: true, + burnable: true + }, + tagList: ["ERC20", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc20'] + }, + { + value: "ozerc20", + displayName: "UUPS ERC20", + description: "UUPS ERC20 contract with:", + opts: { + upgradeable: 'uups', + mintable: true, + pausable: true + }, + tagList: ["ERC20", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc20'] + }, + { + value: "ozerc721", + displayName: "UUPS ERC721 (NFT)", + description: "A simple UUPS ERC721 contract", + opts: { + upgradeable: 'uups' + }, + tagList: ["ERC721", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc721'] + }, + { + value: "ozerc721", + displayName: "UUPS ERC721 (NFT)", + description: "UUPS ERC721 contract with:", + opts: { + upgradeable: 'uups', + mintable: true + }, + tagList: ["ERC721", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc721'] + }, + { + value: "ozerc721", + displayName: "UUPS ERC721 (NFT)", + description: "UUPS ERC721 contract with:", + opts: { + upgradeable: 'uups', + mintable: true, + burnable: true + }, + tagList: ["ERC721", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc721'] + }, + { + value: "ozerc721", + displayName: "UUPS ERC721 (NFT)", + description: "UUPS ERC721 contract with:", + opts: { + upgradeable: 'uups', + mintable: true, + pausable: true + }, + tagList: ["ERC721", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc721'] + }, + { + value: "ozerc1155", + displayName: "UUPS ERC1155", + description: "A simple multi token contract using the UUPS pattern", + opts: { + upgradeable: 'uups' + }, + tagList: ["ERC1155", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc1155'] + }, + { + value: "ozerc1155", + displayName: "UUPS ERC1155", + description: "UUPS ERC1155 with:", + opts: { + upgradeable: 'uups', + mintable: true + }, + tagList: ["ERC1155", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc1155'] + }, + { + value: "ozerc1155", + displayName: "UUPS ERC1155", + description: "UUPS ERC1155 with:", + opts: { + upgradeable: 'uups', + mintable: true, + burnable: true + }, + tagList: ["ERC1155", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc1155'] + }, + { + value: "ozerc1155", + displayName: "UUPS ERC1155", + description: "UUPS ERC1155 with:", + opts: { + upgradeable: 'uups', + mintable: true, + pausable: true + }, + tagList: ["ERC1155", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc1155'] + }, + { + value: "ozerc1155", + displayName: "UUPS ERC1155", + description: "UUPS ERC1155 with:", + opts: { + upgradeable: 'uups', + mintable: true, + burnable: true, + pausable: true + }, + tagList: ["ERC1155", "Solidity"], + // templateType: TEMPLATE_METADATA['ozerc1155'] + } + ] + }, + { + name: "Cookbook", + tooltip: "Cookbook is a Smart Contract Search Tool. Click here to open Cookbook and browse Contracts.", + onClick: async () => { + // await pluginCall('manager', 'activatePlugin', 'cookbookdev') + // await pluginCall('sidePanel', 'focus', 'cookbookdev') + }, + onClickLabel: 'Open Cookbook Plugin', + description: 'Discover more templates!', + items: [], + /* { + value: "token-sale", + displayName: 'Token Sale', + description: "ERC20 token sale contact. Sell tokens for ETH" + }, + { + value: "simple-nft-sale", + displayName: 'Simple Nft Sale', + description: "ERC721 NFT with an adjustable price & to mint free NFTs" + }, + { + value: "Azuki-ERC721A-NFT-Sale-basic", + displayName: 'Azuki ERC721A NFT Sale basic', + description: "An implementation of the ERC721A standard" + }, + { + value: "Azuki-ERC721A-NFT-Sale", + displayName: 'Azuki ERC721A NFT Sale', + description: "An extension of the ERC721A standard with wallet limit" + }, + { + value: "token-staking-with-infinite-rewards", + displayName: 'Token Staking with infinite rewards', + description: "Token staking contract to reward ERC20 tokens for every token staked" + }, + { + value: "nft-staking-with-infinite-rewards", + displayName: 'NFT Staking with infinite rewards', + description: "NFT staking contract to reward exact number of ERC20 tokens per day" + }, + { + value: "basic-dao", + displayName: 'Basic DAO', + description: "A very simple implementation of a DAO" + }, + { + value: "soulbound-nft", + displayName: 'Soulbound NFT', + description: "ERC721 Soulbound NFT with no transfer capability" + }, + { value: "multi-collection-nft-with-burnable-nfts-and-pausable-transfers", + displayName: 'Multi collection NFT', + description: "Multi collection NFT with:", + opts: { + burnable: true, + pausable: true + }, }, + ]*/ + }, + { + name: "0xProject", + items: [ + { value: "zeroxErc20", displayName: "ERC20", tagList: ["ERC20", "Solidity"], description: "A fungible token contract by 0xProject", + // templateType: TEMPLATE_METADATA['zeroxErc20'] + } + ] + }, + { + name: "Gnosis Safe", + items: [ + { value: "gnosisSafeMultisig", tagList: ["Solidity"], // displayName: intl.formatMessage({ id: 'filePanel.multiSigWallet' }), + description: 'Deploy or customize the Gnosis Safe MultiSig Wallet', + // templateType: TEMPLATE_METADATA['gnosisSafeMultisig'] + } + ] + }, + { + name: "Circom ZKP", + items: [ + { value: "semaphore", tagList: ["ZKP", "Circom"], // displayName: intl.formatMessage({ id: 'filePanel.semaphore' }), + description: 'Semaphore protocol for casting a message as a provable group member', + // templateType: TEMPLATE_METADATA['semaphore'] + }, + { value: "hashchecker", tagList: ["ZKP", "Circom"], // displayName: intl.formatMessage({ id: 'filePanel.hashchecker' }), + description: 'Hash checker Circom circuit', + // templateType: TEMPLATE_METADATA['hashchecker'] + }, + { value: "rln", tagList: ["ZKP", "Circom"], + //displayName: intl.formatMessage({ id: 'filePanel.rln' }), + description: 'Rate Limiting Nullifier Circom circuit', + // templateType: TEMPLATE_METADATA['rln'] + } + ] + }, + { + name: "Noir ZKP", + items: [ + { value: "multNr", tagList: ["ZKP", "Noir"], // displayName: intl.formatMessage({ id: 'filePanel.multNr' }), + description: 'A simple multiplier circuit', + // templateType: TEMPLATE_METADATA['multNr'] + } + // { value: "stealthDropNr", tagList: ["ZKP", "Noir"], displayName: intl.formatMessage({ id: 'filePanel.stealthDropNr' }),} + ] + }, + { + name: "Generic ZKP", + items: [ + { + value: "sindriScripts", + tagList: ["ZKP"], + // displayName: intl.formatMessage({ id: 'filePanel.addscriptsindri' }), + description: 'Use the Sindri API to compile and generate proofs', + // templateType: TEMPLATE_METADATA['sindriScripts'] + }, + ], + }, + { + name: "Uniswap V4", + items: [ + { value: "uniswapV4Template", + // displayName: intl.formatMessage({ id: 'filePanel.uniswapV4Template' }), + description: 'Use a Uniswap hook', + // templateType: TEMPLATE_METADATA['uniswapV4Template'] + }, + { + value: "breakthroughLabsUniswapv4Hooks", + // displayName: intl.formatMessage({ id: 'filePanel.breakthroughLabsUniswapv4Hooks' }), + description: 'Use a Uniswap hook developed by Breakthrough Labs', + // templateType: TEMPLATE_METADATA['breakthroughLabsUniswapv4Hooks'] + }, + { + value: "uniswapV4HookBookMultiSigSwapHook", + // displayName: intl.formatMessage({ id: 'filePanel.uniswapV4HookBookMultiSigSwapHook' }), + description: 'Use a MultiSigSwapHook developed by Breakthrough Labs', + // templateType: TEMPLATE_METADATA['uniswapV4HookBookMultiSigSwapHook'] + } + ] + }, + { + name: "Solidity CREATE2", + items: [ + { + value: "contractCreate2Factory", + tagList: ["Solidity"], + // displayName: intl.formatMessage({ id: 'filePanel.addcreate2solidityfactory' }), + description: 'Factory for deploying a contract using the CREATE2 opcode', + // templateType: TEMPLATE_METADATA['contractCreate2Factory'] + }, + { + value: "contractDeployerScripts", + // displayName: intl.formatMessage({ id: 'filePanel.addscriptdeployer' }), + description: 'Script for deploying a contract using the CREATE2 opcode', + // templateType: TEMPLATE_METADATA['contractDeployerScripts'] + } + ] + }, + { + name: "Contract Verification", + items: [ + { + value: "etherscanScripts", + // displayName: intl.formatMessage({ id: 'filePanel.addscriptetherscan' }), + description: 'Script for verifying a Contract in Etherscan', + // templateType: TEMPLATE_METADATA['etherscanScripts'] + }, + ], + }, + { + name: 'GitHub Actions', + items: [ + { value: "runJsTestAction", + // displayName: intl.formatMessage({ id: 'filePanel.tssoltestghaction' }), + description: 'A Mocha Chai test workflow in a GitHub CI', + // templateType: TEMPLATE_METADATA['runJsTestAction'] + }, + { value: "runSolidityUnittestingAction", + // displayName: intl.formatMessage({ id: 'filePanel.solghaction' }), + description: 'Run a Solidity unit test workflow in a GitHub CI', + // templateType: TEMPLATE_METADATA['runSolidityUnittestingAction'] + }, + { + value: "runSlitherAction", + // displayName: intl.formatMessage({ id: 'filePanel.slitherghaction' }), + description: 'Run a Slither security analysis in a GitHub CI', + // templateType: TEMPLATE_METADATA['runSlitherAction'] + } + ], + IsArtefact: true + } +] + +export const metadata = { + 'breakthroughLabsUniswapv4Hooks': { + type: 'git', + url: 'https://github.com/Breakthrough-Labs/Uniswapv4Hooks', + branch: 'foundry_pure', + forceCreateNewWorkspace: true + }, + 'accountAbstraction': { + type: 'git', + url: 'https://github.com/eth-infinitism/account-abstraction', + branch: 'releases/v0.8', + forceCreateNewWorkspace: true + }, + 'uniswapV4Template': { + type: 'git', + url: 'https://github.com/Breakthrough-Labs/v4-template', + branch: 'main', + forceCreateNewWorkspace: true + }, + 'uniswapV4HookBookMultiSigSwapHook': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openPattern', + params: ['Uniswap-V4-HookBook-MultiSigSwapHook', true], + forceCreateNewWorkspace: true, + desktopCompatible: false, + disabled: true + }, + 'token-sale': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openContract', + params: ['token-sale'], + desktopCompatible: false + }, + 'simple-nft-sale': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openContract', + params: ['simple-nft-sale'], + desktopCompatible: false + }, + 'Azuki-ERC721A-NFT-Sale': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openContract', + params: ['Azuki-ERC721A-NFT-Sale'], + desktopCompatible: false + }, + 'Azuki-ERC721A-NFT-Sale-basic': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openContract', + params: ['Azuki-ERC721A-NFT-Sale-basic'], + desktopCompatible: false + }, + 'Azuki-ERC721A-ERC721A': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openContract', + params: ['Azuki-ERC721A-ERC721A'], + desktopCompatible: false + }, + 'token-staking-with-infinite-rewards': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openContract', + params: ['token-staking-with-infinite-rewards'], + desktopCompatible: false + }, + 'nft-staking-with-infinite-rewards': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openContract', + params: ['nft-staking-with-infinite-rewards'], + desktopCompatible: false + }, + 'basic-dao': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openContract', + params: ['basic-dao'], + desktopCompatible: false + }, + 'soulbound-nft': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openContract', + params: ['soulbound-nft'], + desktopCompatible: false + }, + 'multi-collection-nft-with-burnable-nfts-and-pausable-transfers': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openContract', + params: ['multi-collection-nft-with-burnable-nfts-and-pausable-transfers'], + desktopCompatible: false + }, + 'OpenSea-Seaport': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openProtocol', + params: ['OpenSea-Seaport'], + desktopCompatible: false + }, + 'Ethereum-Name-Service': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openProtocol', + params: ['Ethereum-Name-Service'], + desktopCompatible: false + }, + 'Umbra-Cash': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openProtocol', + params: ['Umbra-Cash'], + desktopCompatible: false + }, + 'Aave-V3': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openProtocol', + params: ['Aave-V3'], + desktopCompatible: false + }, + 'ChainLink': { + type: 'plugin', + name: 'cookbookdev', + endpoint: 'openProtocol', + params: ['ChainLink'], + desktopCompatible: false + } +} + +// +// { +// templatesRepository.map(template => { +// return ( +// +// { +// template.items.map((item, index) => { + +// item.templateType = metadata[item.value] +// if (item.templateType && item.templateType.desktopCompatible === false && isElectron()) { +// return (<>) +// } + +// if (item.templateType && item.templateType.disabled === true) return + +// if (!item.opts) { +// return ( +//
+// +//
+//
+//
+// {item.description && {item.description}} +//
+//
+// {(item.opts && item.opts.upgradeable && item.opts.upgradeable === 'uups') && Upgradeable-UUPS} +// {(item.opts && item.opts.mintable) && mintable} +// {(item.opts && item.opts.burnable) && burnable} +// {(item.opts && item.opts.pausable) && pausable} +//
+//
+//
+// {(!template.IsArtefact || !item.IsArtefact) && +// { +// if ((item.value as string).toLowerCase().includes('ai')) { +// // this.aiWorkspaceGenerate() +// } else { +// // createWorkspace(item, template) +// } +// }} +// className="btn btn-sm me-2 border border-primary" +// data-template-name={item.name} +// > +// {isElectron() ? +// <>Create : 'Create'} +// +// } +// {item.templateType && item.templateType.forceCreateNewWorkspace ? <> : isElectron() ? + +//
+// +// addToCurrentElectronFolder(item, template.name)} +// className="btn btn-sm border" +// > +// +// Add here +// +// +//
+// : +// +// addToCurrentWorkspace(item, template)} +// className="btn btn-sm border" +// > +// Add to current +// +// } +//
+//
+//
+//
+// ) // end return +// } // end if +// }) // end map +// } +// {template.name === 'Cookbook' && +//
+// {template.description} +// template.onClick()}>{template.onClickLabel} +//
+//
} +//
+// ) +// }) +// } +//
diff --git a/libs/remix-ui/generic-modal/types/template-explorer-types.ts b/libs/remix-ui/generic-modal/types/template-explorer-types.ts new file mode 100644 index 00000000000..db7ee583943 --- /dev/null +++ b/libs/remix-ui/generic-modal/types/template-explorer-types.ts @@ -0,0 +1,17 @@ + +export interface TemplateExplorerWizardState { + steps: TemplateExplorerWizardSteps + workspaceTemplateChosen: string + workspaceTemplateGroupChosen: string + workspaceName: string + defaultWorkspaceName: string + topLeftNagivationName: string + initializeAsGitRepo: boolean +} + +export enum TemplateExplorerWizardSteps { + SELECT_TEMPLATE = 'SELECT_TEMPLATE', + GENERATE_TEMPLATE = 'GENERATE_TEMPLATE', + MODIFY_WORKSPACE = 'MODIFY_WORKSPACE', + REVIEW_WORKSPACE = 'REVIEW_WORKSPACE' +} diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx index 36b0afe9beb..ad041af201f 100644 --- a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx @@ -13,13 +13,12 @@ declare global { const _paq = window._paq = window._paq || [] interface RemixUIGridCellProps { - plugin: any pinned?: boolean pinStateCallback?: any logo?: string logos?: string[] logoURL?: string - title: string + title?: string titleTooltip?: string hideTitle?: boolean tagList?: string[] // max 8, others will be ignored @@ -28,7 +27,7 @@ interface RemixUIGridCellProps { children?: ReactNode expandViewEl?: any handleExpand?: any - id: string + id?: string searchKeywords?: string[] } diff --git a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx index c82d98399bb..433522dc2e6 100644 --- a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx +++ b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx @@ -5,7 +5,7 @@ import HomeTabTitle from './components/homeTabTitle' import HomeTabRecentWorkspaces from './components/homeTabRecentWorkspaces' import HomeTabScamAlert from './components/homeTabScamAlert' import HomeTabFeaturedPlugins from './components/homeTabFeaturedPlugins' -import { AppContext, appPlatformTypes, platformContext } from '@remix-ui/app' +import { appActionTypes, AppContext, appPlatformTypes, platformContext } from '@remix-ui/app' import { HomeTabFileElectron } from './components/homeTabFileElectron' import HomeTabUpdates from './components/homeTabUpdates' import { FormattedMessage } from 'react-intl' @@ -73,22 +73,17 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => { _paq.push(['trackEvent', 'hometab', 'header', 'Create a new workspace']) } + function openGenericModal(event): void { + appContext.appStateDispatch({ + type: appActionTypes.showGenericModal, + payload: true + }) + } + // if (appContext.appState.connectedToDesktop != desktopConnectionType.disabled) { // return (<>) // } - const openTemplateExplorer = async () => { - console.log('openTemplateExplorer') - await plugin.call('notification', 'templateExplorer', { - id: 'templateExplorer', - title: 'Explore all templates', - message:
Explore all templates
, - okLabel: 'Explore all templates', - okFn: () => {} - }) - _paq.push(['trackEvent', 'hometab', 'header', 'Explore all templates']) - } - return (
@@ -97,7 +92,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
- +
diff --git a/libs/remix-ui/modal-dialog/src/lib/types/index.ts b/libs/remix-ui/modal-dialog/src/lib/types/index.ts index cd3f9f80af7..d828a30a303 100644 --- a/libs/remix-ui/modal-dialog/src/lib/types/index.ts +++ b/libs/remix-ui/modal-dialog/src/lib/types/index.ts @@ -31,4 +31,5 @@ export interface ModalDialogProps { cancelBtnClass?: string, preventBlur?: boolean placeholderText?: string + genericData?: any } diff --git a/libs/remix-ui/workspace/src/index.ts b/libs/remix-ui/workspace/src/index.ts index 12185dd4549..18bed427ce9 100644 --- a/libs/remix-ui/workspace/src/index.ts +++ b/libs/remix-ui/workspace/src/index.ts @@ -1,4 +1,5 @@ export * from './lib/providers/FileSystemProvider' export * from './lib/contexts' export * from './lib/utils/constants' +export * from './lib/utils/templates' export { FileType, FilePanelType } from './lib/types/index' diff --git a/libs/remix-ui/workspace/src/lib/utils/templates.ts b/libs/remix-ui/workspace/src/lib/utils/templates.ts new file mode 100644 index 00000000000..760c1ce51e2 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/utils/templates.ts @@ -0,0 +1,429 @@ +import { Template, TemplateGroup } from "@remix-ui/workspace" +export const templates = (intl: any, plugin: any): TemplateGroup[] => { + + return [ + { + name: "Generic", + items: [ + { value: "remixDefault", tagList: ["Solidity"], displayName: intl.formatMessage({ id: 'filePanel.basic' }), description: 'The default project' }, + { value: "blank", displayName: intl.formatMessage({ id: 'filePanel.blank' }), IsArtefact: true, description: 'A blank project' }, + { value: "simpleEip7702", displayName: 'Simple EIP 7702', IsArtefact: true, description: 'Pectra upgrade allowing externally owned accounts (EOAs) to run contract code.' }, + { value: "accountAbstraction", displayName: 'Account Abstraction', IsArtefact: true, description: 'A repo about ERC-4337 and EIP-7702' }, + { value: 'remixAiTemplate', tagList: ['AI'], displayName: 'RemixAI Template Generation', IsArtefact: true, description: 'AI generated workspace. Workspace gets generated with a user prompt.' }, + { value: "introToEIP7702", displayName: 'Intro to EIP-7702', IsArtefact: true, description: 'A contract for demoing EIP-7702' }, + ] + }, + { + name: "OpenZeppelin", + hasOptions: true, + items: [ + { + value: "ozerc20", + displayName: "ERC20", + tagList: ["ERC20", "Solidity"], + description: 'A customizable fungible token contract' + }, + { + value: "ozerc20", + displayName: "ERC20", + description: "An ERC20 contract with:", + tagList: ["Solidity"], + opts: { + mintable: true + } + }, + { + value: "ozerc20", + displayName: "ERC20", + description: "An ERC20 contract with:", + tagList: ["Solidity", "ERC20"], + opts: { + mintable: true, + burnable: true + }, + }, + { + value: "ozerc20", + displayName: "ERC20", + description: "An ERC20 contract with:", + opts: { + mintable: true, + pausable: true + }, + tagList: ["ERC20", "Solidity"] + }, + { + value: "ozerc721", + displayName: "ERC721 (NFT)", + tagList: ["ERC721", "Solidity"], + description: 'A customizable non-fungible token (NFT) contract' + }, + { + value: "ozerc721", + displayName: "ERC721 (NFT)", + description: "An ERC721 contract with:", + tagList: ["Solidity", "ERC721"], + opts: { + mintable: true + } + }, + { + value: "ozerc721", + displayName: "ERC721 (NFT)", + description: "An ERC721 contract with:", + opts: { + mintable: true, + burnable: true + }, + tagList: ["ERC721", "Solidity"] + }, + { + value: "ozerc721", + displayName: "ERC721 (NFT)", + description: "An ERC721 contract with:", + opts: { + mintable: true, + pausable: true + }, + tagList: ["ERC721", "Solidity"] + }, + { + value: "ozerc1155", + tagList: ["Solidity"], + displayName: "ERC1155", + description: 'A customizable multi token contract' + }, + { + value: "ozerc1155", + displayName: "ERC1155", + tagList: ["Solidity"], + description: "An ERC1155 contract with:", + opts: { + mintable: true + } + }, + { + value: "ozerc1155", + displayName: "ERC1155", + description: "An ERC1155 contract with:", + opts: { + mintable: true, + burnable: true + }, + tagList: ["ERC1155", "Solidity"] + }, + { + value: "ozerc1155", + displayName: "ERC1155", + description: "An ERC1155 contract with:", + tagList: ["ERC1155"], + opts: { + mintable: true, + pausable: true + } + } + ] + }, + { + name: "OpenZeppelin Proxy", + items: [ + { + value: "ozerc20", + displayName: "UUPS ERC20", + description: "A simple ERC20 contract using the Universal Upgradeable Proxy Standard (UUPS) pattern", + opts: { + upgradeable: 'uups' + }, + tagList: ["ERC20", "Solidity"] + }, + { + value: "ozerc20", + displayName: "UUPS ERC20", + description: "UUPS ERC20 contract with:", + opts: { + upgradeable: 'uups', + mintable: true + }, + tagList: ["ERC20", "Solidity"] + }, + { + value: "ozerc20", + displayName: "UUPS ERC20", + description: "UUPS ERC20 contract with:", + opts: { + upgradeable: 'uups', + mintable: true, + burnable: true + }, + tagList: ["ERC20", "Solidity"] + }, + { + value: "ozerc20", + displayName: "UUPS ERC20", + description: "UUPS ERC20 contract with:", + opts: { + upgradeable: 'uups', + mintable: true, + pausable: true + }, + tagList: ["ERC20", "Solidity"] + }, + { + value: "ozerc721", + displayName: "UUPS ERC721 (NFT)", + description: "A simple UUPS ERC721 contract", + opts: { + upgradeable: 'uups' + }, + tagList: ["ERC721", "Solidity"] + }, + { + value: "ozerc721", + displayName: "UUPS ERC721 (NFT)", + description: "UUPS ERC721 contract with:", + opts: { + upgradeable: 'uups', + mintable: true + }, + tagList: ["ERC721", "Solidity"] + }, + { + value: "ozerc721", + displayName: "UUPS ERC721 (NFT)", + description: "UUPS ERC721 contract with:", + opts: { + upgradeable: 'uups', + mintable: true, + burnable: true + }, + tagList: ["ERC721", "Solidity"] + }, + { + value: "ozerc721", + displayName: "UUPS ERC721 (NFT)", + description: "UUPS ERC721 contract with:", + opts: { + upgradeable: 'uups', + mintable: true, + pausable: true + }, + tagList: ["ERC721", "Solidity"] + }, + { + value: "ozerc1155", + displayName: "UUPS ERC1155", + description: "A simple multi token contract using the UUPS pattern", + opts: { + upgradeable: 'uups' + }, + tagList: ["ERC1155", "Solidity"] + }, + { + value: "ozerc1155", + displayName: "UUPS ERC1155", + description: "UUPS ERC1155 with:", + opts: { + upgradeable: 'uups', + mintable: true + }, + tagList: ["ERC1155", "Solidity"] + }, + { + value: "ozerc1155", + displayName: "UUPS ERC1155", + description: "UUPS ERC1155 with:", + opts: { + upgradeable: 'uups', + mintable: true, + burnable: true + }, + tagList: ["ERC1155", "Solidity"] + }, + { + value: "ozerc1155", + displayName: "UUPS ERC1155", + description: "UUPS ERC1155 with:", + opts: { + upgradeable: 'uups', + mintable: true, + pausable: true + }, + tagList: ["ERC1155", "Solidity"] + }, + { + value: "ozerc1155", + displayName: "UUPS ERC1155", + description: "UUPS ERC1155 with:", + opts: { + upgradeable: 'uups', + mintable: true, + burnable: true, + pausable: true + }, + tagList: ["ERC1155", "Solidity"] + } + ] + }, + { + name: "Cookbook", + tooltip: "Cookbook is a Smart Contract Search Tool. Click here to open Cookbook and browse Contracts.", + onClick: async () => { + await plugin.call('manager', 'activatePlugin', 'cookbookdev') + await plugin.call('sidePanel', 'focus', 'cookbookdev') + }, + onClickLabel: 'Open Cookbook Plugin', + description: 'Discover more templates!', + items: [], + /* { + value: "token-sale", + displayName: 'Token Sale', + description: "ERC20 token sale contact. Sell tokens for ETH" + }, + { + value: "simple-nft-sale", + displayName: 'Simple Nft Sale', + description: "ERC721 NFT with an adjustable price & to mint free NFTs" + }, + { + value: "Azuki-ERC721A-NFT-Sale-basic", + displayName: 'Azuki ERC721A NFT Sale basic', + description: "An implementation of the ERC721A standard" + }, + { + value: "Azuki-ERC721A-NFT-Sale", + displayName: 'Azuki ERC721A NFT Sale', + description: "An extension of the ERC721A standard with wallet limit" + }, + { + value: "token-staking-with-infinite-rewards", + displayName: 'Token Staking with infinite rewards', + description: "Token staking contract to reward ERC20 tokens for every token staked" + }, + { + value: "nft-staking-with-infinite-rewards", + displayName: 'NFT Staking with infinite rewards', + description: "NFT staking contract to reward exact number of ERC20 tokens per day" + }, + { + value: "basic-dao", + displayName: 'Basic DAO', + description: "A very simple implementation of a DAO" + }, + { + value: "soulbound-nft", + displayName: 'Soulbound NFT', + description: "ERC721 Soulbound NFT with no transfer capability" + }, + { value: "multi-collection-nft-with-burnable-nfts-and-pausable-transfers", + displayName: 'Multi collection NFT', + description: "Multi collection NFT with:", + opts: { + burnable: true, + pausable: true + }, }, + ]*/ + }, + { + name: "0xProject", + items: [ + { value: "zeroxErc20", displayName: "ERC20", tagList: ["ERC20", "Solidity"], description: "A fungible token contract by 0xProject" } + ] + }, + { + name: "Gnosis Safe", + items: [ + { value: "gnosisSafeMultisig", tagList: ["Solidity"], displayName: intl.formatMessage({ id: 'filePanel.multiSigWallet' }), description: 'Deploy or customize the Gnosis Safe MultiSig Wallet' } + ] + }, + { + name: "Circom ZKP", + items: [ + { value: "semaphore", tagList: ["ZKP", "Circom"], displayName: intl.formatMessage({ id: 'filePanel.semaphore' }), description: 'Semaphore protocol for casting a message as a provable group member' }, + { value: "hashchecker", tagList: ["ZKP", "Circom"], displayName: intl.formatMessage({ id: 'filePanel.hashchecker' }), description: 'Hash checker Circom circuit' }, + { value: "rln", tagList: ["ZKP", "Circom"], displayName: intl.formatMessage({ id: 'filePanel.rln' }), description: 'Rate Limiting Nullifier Circom circuit' } + ] + }, + { + name: "Noir ZKP", + items: [ + { value: "multNr", tagList: ["ZKP", "Noir"], displayName: intl.formatMessage({ id: 'filePanel.multNr' }), description: 'A simple multiplier circuit' } + // { value: "stealthDropNr", tagList: ["ZKP", "Noir"], displayName: intl.formatMessage({ id: 'filePanel.stealthDropNr' }), description: 'A stealth drop implementaion built in Noir' } + ] + }, + { + name: "Generic ZKP", + items: [ + { + value: "sindriScripts", + tagList: ["ZKP"], + displayName: intl.formatMessage({ id: 'filePanel.addscriptsindri' }), + description: 'Use the Sindri API to compile and generate proofs' + }, + ], + }, + { + name: "Uniswap V4", + items: [ + { value: "uniswapV4Template", + displayName: intl.formatMessage({ id: 'filePanel.uniswapV4Template' }), + description: 'Use a Uniswap hook' + }, + { + value: "breakthroughLabsUniswapv4Hooks", + displayName: intl.formatMessage({ id: 'filePanel.breakthroughLabsUniswapv4Hooks' }), + description: 'Use a Uniswap hook developed by Breakthrough Labs' + }, + { + value: "uniswapV4HookBookMultiSigSwapHook", + displayName: intl.formatMessage({ id: 'filePanel.uniswapV4HookBookMultiSigSwapHook' }), + description: 'Use a MultiSigSwapHook developed by Breakthrough Labs' + } + ] + }, + { + name: "Solidity CREATE2", + items: [ + { + value: "contractCreate2Factory", + tagList: ["Solidity"], + displayName: intl.formatMessage({ id: 'filePanel.addcreate2solidityfactory' }), + description: 'Factory for deploying a contract using the CREATE2 opcode' + }, + { + value: "contractDeployerScripts", + displayName: intl.formatMessage({ id: 'filePanel.addscriptdeployer' }), + description: 'Script for deploying a contract using the CREATE2 opcode' + } + ] + }, + { + name: "Contract Verification", + items: [ + { + value: "etherscanScripts", + displayName: intl.formatMessage({ id: 'filePanel.addscriptetherscan' }), + description: 'Script for verifying a Contract in Etherscan' + }, + ], + }, + { + name: 'GitHub Actions', + items: [ + { value: "runJsTestAction", + displayName: intl.formatMessage({ id: 'filePanel.tssoltestghaction' }), + description: 'A Mocha Chai test workflow in a GitHub CI' + }, + { value: "runSolidityUnittestingAction", + displayName: intl.formatMessage({ id: 'filePanel.solghaction' }), + description: 'Run a Solidity unit test workflow in a GitHub CI' + }, + { + value: "runSlitherAction", + displayName: intl.formatMessage({ id: 'filePanel.slitherghaction' }), + description: 'Run a Slither security analysis in a GitHub CI' + } + ], + IsArtefact: true + } + ] +} From 8c949f3a78cdd436d2ce72685508a570ab32c10b Mon Sep 17 00:00:00 2001 From: ci-bot Date: Tue, 16 Sep 2025 15:36:53 +0100 Subject: [PATCH 04/15] rename plugin files appropriately. --- apps/remix-ide/src/app.ts | 2 +- .../src/app/plugins/remix-generic-modal.tsx | 12 ++++++------ apps/remix-ide/src/remixAppManager.ts | 4 ++-- .../app/src/lib/remix-app/remix-app.tsx | 4 ++-- libs/remix-ui/generic-modal/src/index.ts | 1 - .../reducers/template-explorer-reducer.tsx | 0 .../src/components/template-explorer-body.tsx | 0 .../src/components/template-explorer.tsx | 0 .../src/components/topCard.tsx | 0 .../template-explorer-modal/src/index.ts | 1 + .../lib/remix-ui-template-explorer-modal.css} | 18 +++++++++--------- .../lib/remix-ui-template-explorer-modal.tsx} | 14 +++++++------- .../src/utils/helpers.tsx | 0 .../types/template-explorer-types.ts | 0 tsconfig.paths.json | 3 +++ 15 files changed, 31 insertions(+), 28 deletions(-) delete mode 100644 libs/remix-ui/generic-modal/src/index.ts rename libs/remix-ui/{generic-modal => template-explorer-modal}/reducers/template-explorer-reducer.tsx (100%) rename libs/remix-ui/{generic-modal => template-explorer-modal}/src/components/template-explorer-body.tsx (100%) rename libs/remix-ui/{generic-modal => template-explorer-modal}/src/components/template-explorer.tsx (100%) rename libs/remix-ui/{generic-modal => template-explorer-modal}/src/components/topCard.tsx (100%) create mode 100644 libs/remix-ui/template-explorer-modal/src/index.ts rename libs/remix-ui/{generic-modal/src/lib/remix-ui-generic-modal.css => template-explorer-modal/src/lib/remix-ui-template-explorer-modal.css} (68%) rename libs/remix-ui/{generic-modal/src/lib/remix-ui-generic-modal.tsx => template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx} (64%) rename libs/remix-ui/{generic-modal => template-explorer-modal}/src/utils/helpers.tsx (100%) rename libs/remix-ui/{generic-modal => template-explorer-modal}/types/template-explorer-types.ts (100%) diff --git a/apps/remix-ide/src/app.ts b/apps/remix-ide/src/app.ts index 77f6c478ecf..03dc8c9d25b 100644 --- a/apps/remix-ide/src/app.ts +++ b/apps/remix-ide/src/app.ts @@ -111,7 +111,7 @@ import Terminal from './app/panels/terminal' import TabProxy from './app/panels/tab-proxy.js' import { Plugin } from '@remixproject/engine' import BottomBarPanel from './app/components/bottom-bar-panel' -import { TemplateExplorerModalPlugin } from './app/plugins/remix-generic-modal' +import { TemplateExplorerModalPlugin } from './app/plugins/remix-template-explorer-modal' const _paq = (window._paq = window._paq || []) diff --git a/apps/remix-ide/src/app/plugins/remix-generic-modal.tsx b/apps/remix-ide/src/app/plugins/remix-generic-modal.tsx index 0e0f66860f0..afa0638d94d 100644 --- a/apps/remix-ide/src/app/plugins/remix-generic-modal.tsx +++ b/apps/remix-ide/src/app/plugins/remix-generic-modal.tsx @@ -4,10 +4,10 @@ import { AppAction, AppState } from '@remix-ui/app' import { PluginViewWrapper } from '@remix-ui/helper' import { Plugin } from '@remixproject/engine' import { EventEmitter } from 'events' -import { RemixUiGenericModal, RemixUiGenericModalProps } from 'libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal' +import { RemixUiTemplateExplorerModal, RemixUiTemplateExplorerModalProps } from 'libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal' const pluginProfile = { - name: 'remix-generic-modal', + name: 'remix-template-explorer-modal', displayName: 'Remix Generic Modal', description: 'Remix Generic Modal for every type of content meant for a modal', methods: ['openModal'] @@ -21,7 +21,7 @@ export class TemplateExplorerModalPlugin extends Plugin { constructor() { super(pluginProfile) this.element = document.createElement('div') - this.element.setAttribute('id', 'remix-generic-modal') + this.element.setAttribute('id', 'remix-template-explorer-modal') this.dispatch = () => { } this.event = new EventEmitter() } @@ -45,7 +45,7 @@ export class TemplateExplorerModalPlugin extends Plugin { render() { return ( -
+
) @@ -57,9 +57,9 @@ export class TemplateExplorerModalPlugin extends Plugin { }) } - updateComponent(state: RemixUiGenericModalProps, appState: AppState) { + updateComponent(state: RemixUiTemplateExplorerModalProps, appState: AppState) { return ( - {
- {appState.genericModalState.showModal && } + {appState.genericModalState.showModal && } diff --git a/libs/remix-ui/generic-modal/src/index.ts b/libs/remix-ui/generic-modal/src/index.ts deleted file mode 100644 index 2c6c5ec82f7..00000000000 --- a/libs/remix-ui/generic-modal/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './lib/remix-ui-generic-modal' diff --git a/libs/remix-ui/generic-modal/reducers/template-explorer-reducer.tsx b/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx similarity index 100% rename from libs/remix-ui/generic-modal/reducers/template-explorer-reducer.tsx rename to libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx diff --git a/libs/remix-ui/generic-modal/src/components/template-explorer-body.tsx b/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx similarity index 100% rename from libs/remix-ui/generic-modal/src/components/template-explorer-body.tsx rename to libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx diff --git a/libs/remix-ui/generic-modal/src/components/template-explorer.tsx b/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx similarity index 100% rename from libs/remix-ui/generic-modal/src/components/template-explorer.tsx rename to libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx diff --git a/libs/remix-ui/generic-modal/src/components/topCard.tsx b/libs/remix-ui/template-explorer-modal/src/components/topCard.tsx similarity index 100% rename from libs/remix-ui/generic-modal/src/components/topCard.tsx rename to libs/remix-ui/template-explorer-modal/src/components/topCard.tsx diff --git a/libs/remix-ui/template-explorer-modal/src/index.ts b/libs/remix-ui/template-explorer-modal/src/index.ts new file mode 100644 index 00000000000..7186a278de7 --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/index.ts @@ -0,0 +1 @@ +export * from './lib/remix-ui-template-explorer-modal' diff --git a/libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.css b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.css similarity index 68% rename from libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.css rename to libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.css index 66f627594ce..f5add1d6947 100644 --- a/libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.css +++ b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.css @@ -1,4 +1,4 @@ -.generic-modal-background { +.template-explorer-modal-background { position: fixed; display: flex; justify-content: center; @@ -10,20 +10,20 @@ background-color: transparent; } -.generic-modal-container { +.template-explorer-modal-container { border-radius: 10px; display: flex; box-shadow: 0 0 5px 5px rgba(0, 0, 0, 0.1); flex-direction: column; } -.generic-modal-close-container { +.template-explorer-modal-close-container { display: flex; justify-content: flex-end; align-items: center; } -.generic-modal-close-button { +.template-explorer-modal-close-button { background-color: transparent; border: none; cursor: pointer; @@ -39,23 +39,23 @@ border: 2px dashed var(--bs-info-border-subtle); } -.generic-modal-close-button:hover { +.template-explorer-modal-close-button:hover { background-color: transparent; } -.generic-modal-close-button:focus { +.template-explorer-modal-close-button:focus { background-color: transparent; } -.generic-modal-close-button:active { +.template-explorer-modal-close-button:active { background-color: transparent; } -.generic-modal-close-button:disabled { +.template-explorer-modal-close-button:disabled { background-color: transparent; } -.generic-modal-close-button:focus-visible { +.template-explorer-modal-close-button:focus-visible { background-color: transparent; } diff --git a/libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.tsx b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx similarity index 64% rename from libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.tsx rename to libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx index 1f9657a72c3..af3a87362fa 100644 --- a/libs/remix-ui/generic-modal/src/lib/remix-ui-generic-modal.tsx +++ b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx @@ -1,10 +1,10 @@ import React from 'react' -import './remix-ui-generic-modal.css' +import './remix-ui-template-explorer-modal.css' import { appActionTypes, AppState } from '@remix-ui/app' import { TopCard, TopCardProps } from '../components/topCard' import { TemplateExplorerBody } from '../components/template-explorer-body' -export interface RemixUiGenericModalProps { +export interface RemixUiTemplateExplorerModalProps { dispatch: any appState: AppState plugin: any @@ -35,13 +35,13 @@ const topCards: TopCardProps[] = [ ] -export function RemixUiGenericModal (props: RemixUiGenericModalProps) { +export function RemixUiTemplateExplorerModal (props: RemixUiTemplateExplorerModalProps) { return ( -
-
-
-
diff --git a/libs/remix-ui/generic-modal/src/utils/helpers.tsx b/libs/remix-ui/template-explorer-modal/src/utils/helpers.tsx similarity index 100% rename from libs/remix-ui/generic-modal/src/utils/helpers.tsx rename to libs/remix-ui/template-explorer-modal/src/utils/helpers.tsx diff --git a/libs/remix-ui/generic-modal/types/template-explorer-types.ts b/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts similarity index 100% rename from libs/remix-ui/generic-modal/types/template-explorer-types.ts rename to libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts diff --git a/tsconfig.paths.json b/tsconfig.paths.json index c3429db21b6..7e94c54b52a 100644 --- a/tsconfig.paths.json +++ b/tsconfig.paths.json @@ -208,6 +208,9 @@ ], "@remix-ui/top-bar": [ "libs/remix-ui/top-bar/src/index.ts" + ], + "@remix-ui/template-explorer-modal": [ + "libs/remix-ui/template-explorer-modal/src/index.ts" ] } } From 632d47a0aae5e2fc5b62a9bfce6f2b6becc8204e Mon Sep 17 00:00:00 2001 From: ci-bot Date: Wed, 17 Sep 2025 15:17:57 +0100 Subject: [PATCH 05/15] rename plugin file. Add ts compiler option --- ...remix-generic-modal.tsx => remix-template-explorer-modal.tsx} | 0 tsconfig.base.json | 1 + 2 files changed, 1 insertion(+) rename apps/remix-ide/src/app/plugins/{remix-generic-modal.tsx => remix-template-explorer-modal.tsx} (100%) diff --git a/apps/remix-ide/src/app/plugins/remix-generic-modal.tsx b/apps/remix-ide/src/app/plugins/remix-template-explorer-modal.tsx similarity index 100% rename from apps/remix-ide/src/app/plugins/remix-generic-modal.tsx rename to apps/remix-ide/src/app/plugins/remix-template-explorer-modal.tsx diff --git a/tsconfig.base.json b/tsconfig.base.json index a9630ce5e6f..86c3d34538d 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -11,6 +11,7 @@ "sourceMap": true, "declaration": false, "moduleResolution": "node", + "resolveJsonModule": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "allowSyntheticDefaultImports": true, From e0bbc318d6c4b8138e470384135731c5f6701465 Mon Sep 17 00:00:00 2001 From: ci-bot Date: Mon, 22 Sep 2025 22:15:52 +0100 Subject: [PATCH 06/15] fix styles. add logo update helpers.tsx --- .../src/assets/img/openzeppelin-logo.png | Bin 0 -> 24559 bytes .../app/src/lib/remix-app/remix-app.tsx | 5 +- .../context/template-explorer-context.tsx | 139 ++++++++ .../reducers/template-explorer-reducer.tsx | 38 +- .../src/components/template-explorer-body.tsx | 16 +- .../src/components/template-explorer.tsx | 336 ++++++++---------- .../src/components/topCard.tsx | 19 +- .../src/components/topCards.tsx | 110 ++++++ .../lib/remix-ui-template-explorer-modal.css | 7 + .../lib/remix-ui-template-explorer-modal.tsx | 64 ++-- .../src/lib/search-icon.svg | 18 + .../src/utils/helpers.tsx | 90 ++--- .../types/template-explorer-types.ts | 99 +++++- 13 files changed, 636 insertions(+), 305 deletions(-) create mode 100644 apps/remix-ide/src/assets/img/openzeppelin-logo.png create mode 100644 libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx create mode 100644 libs/remix-ui/template-explorer-modal/src/components/topCards.tsx create mode 100644 libs/remix-ui/template-explorer-modal/src/lib/search-icon.svg diff --git a/apps/remix-ide/src/assets/img/openzeppelin-logo.png b/apps/remix-ide/src/assets/img/openzeppelin-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9c3fcb27531c838dfec01f8f98f93c90f2967725 GIT binary patch literal 24559 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 PsWU?Mh3#z&N;vyJaS^<{ literal 0 HcmV?d00001 diff --git a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx index f0b8084d9f4..499e5c83bce 100644 --- a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx @@ -59,8 +59,9 @@ const RemixApp = (props: IRemixAppUi) => { okFn: () => { }, cancelLabel: 'Default Cancel Label', cancelFn: () => { }, - width: '892px', - height: '768px' + width: '640px', + height: '720px', + showModal: true } }) diff --git a/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx b/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx new file mode 100644 index 00000000000..030148e3ef4 --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx @@ -0,0 +1,139 @@ +import React, { createContext, useContext, useEffect, useMemo, useReducer, useState } from 'react' +import { TemplateCategory, TemplateExplorerContextType, TemplateExplorerWizardAction, TemplateItem } from '../types/template-explorer-types' +import { initialState, templateExplorerReducer } from '../reducers/template-explorer-reducer' +import { metadata, templatesRepository } from '../src/utils/helpers' +import { AppContext } from '@remix-ui/app' + +export const TemplateExplorerContext = createContext({} as any) + +export const TemplateExplorerProvider = ({ children }: { children: React.ReactNode }) => { + // const [templateRepository, setTemplateRepository] = useState([]) + // const [metadata, setMetadata] = useState([]) + // const [selectedTag, setSelectedTag] = useState(null) + // const [recentBump, setRecentBump] = useState(0) + const [state, dispatch] = useReducer(templateExplorerReducer, initialState) + const appContext = useContext(AppContext) + + useEffect(() => { + dispatch({ type: TemplateExplorerWizardAction.SET_METADATA, payload: metadata }) + dispatch({ type: TemplateExplorerWizardAction.SET_TEMPLATE_REPOSITORY, payload: templatesRepository }) + + }, []) + + const allTags = useMemo((): string[] => { + const tags: string[] = [] + + if (state.templateRepository && Array.isArray(state.templateRepository)) { + state.templateRepository.forEach((template: any) => { + if (template && template.items && Array.isArray(template.items)) { + template.items.forEach((item: any) => { + if (item && item.tagList && Array.isArray(item.tagList)) { + item.tagList.forEach((tag: string) => { + if (typeof tag === 'string' && !tags.includes(tag)) { + tags.push(tag) + } + }) + } + }) + } + }) + } + + return tags.sort() + }, []) + + // Recent templates (before filteredTemplates so it can be referenced later) + const recentTemplates = useMemo((): TemplateItem[] => { + try { + const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null + const list: string[] = raw ? JSON.parse(raw) : [] + const items: TemplateItem[] = [] + if (Array.isArray(state.templateRepository)) { + list.forEach((val) => { + for (const group of state.templateRepository as any[]) { + if (group && Array.isArray(group.items)) { + const found = group.items.find((it: any) => it && it.value === val) + if (found) { + items.push(found) + break + } + } + } + }) + } + //tag filter + const filtered = state.selectedTag + ? items.filter((it: any) => it && Array.isArray(it.tagList) && it.tagList.includes(state.selectedTag)) + : items + return filtered + } catch (e) { + return [] + } + }, [state.selectedTag, state.recentBump]) + + // Filter templates based on selected tag + const filteredTemplates = useMemo((): TemplateCategory[] => { + if (!state.selectedTag || !state.templateRepository || !Array.isArray(state.templateRepository)) { + return state.templateRepository as TemplateCategory[] || [] + } + + return (state.templateRepository as TemplateCategory[]).map((template: any) => ({ + ...template, + items: template.items.filter((item: any) => + item && item.tagList && Array.isArray(item.tagList) && item.tagList.includes(state.selectedTag) + ) + })).filter((template: any) => template && template.items && template.items.length > 0) + }, [state.selectedTag]) + + // Dedupe templates across the whole page and avoid showing ones already in recents + const dedupedTemplates = useMemo((): TemplateCategory[] => { + const recentSet = new Set((recentTemplates || []).map((t: any) => t && t.value)) + const seen = new Set() + const makeUniqueItems = (items: any[]) => { + const unique: any[] = [] + for (const it of items || []) { + const val = it && it.value + if (!val) continue + if (recentSet.has(val)) continue + if (seen.has(val)) continue + seen.add(val) + unique.push(it) + } + return unique + } + return (filteredTemplates || []).map((group: any) => ({ + ...group, + items: makeUniqueItems(group && group.items ? group.items : []) + })).filter((g: any) => g && g.items && g.items.length > 0) + }, [filteredTemplates, recentTemplates]) + + const handleTagClick = (tag: string) => { + dispatch({ type: TemplateExplorerWizardAction.SET_SELECTED_TAG, payload: state.selectedTag === tag ? null : tag }) + } + + const clearFilter = () => { + dispatch({ type: TemplateExplorerWizardAction.SET_SELECTED_TAG, payload: null }) + } + + const RECENT_KEY = 'remix.recentTemplates' + + const addRecentTemplate = (template: TemplateItem) => { + try { + const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null + const list: string[] = raw ? JSON.parse(raw) : [] + const filtered = list.filter((v) => v !== template.value) + filtered.unshift(template.value) + const trimmed = filtered.slice(0, 4) + if (typeof window !== 'undefined') window.localStorage.setItem(RECENT_KEY, JSON.stringify(trimmed)) + dispatch({ type: TemplateExplorerWizardAction.SET_RECENT_BUMP, payload: state.recentBump + 1 }) + } catch (e) { + + } + } + + return ( + + {children} + + ) +} diff --git a/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx b/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx index d6e961221f0..8f4e2ad5518 100644 --- a/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx +++ b/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx @@ -1,19 +1,49 @@ import React from 'react' -import { TemplateExplorerWizardState, TemplateExplorerWizardSteps } from '../types/template-explorer-types' +import { MetadataType, TemplateExplorerWizardAction, TemplateExplorerWizardState, TemplateExplorerWizardSteps } from '../types/template-explorer-types' +import { metadata, templatesRepository } from '../src/utils/helpers' -const initialState: TemplateExplorerWizardState = { +export const initialState: TemplateExplorerWizardState = { steps: TemplateExplorerWizardSteps.SELECT_TEMPLATE, workspaceTemplateChosen: '', workspaceTemplateGroupChosen: '', workspaceName: '', defaultWorkspaceName: '', topLeftNagivationName: '', - initializeAsGitRepo: false + initializeAsGitRepo: false, + workspaceGeneratedWithAi: false, + searchTerm: '', + metadata: metadata as MetadataType, + templateRepository: templatesRepository, + selectedTag: null } export const templateExplorerReducer = (state: TemplateExplorerWizardState, action: any) => { switch (action.type) { - case 'SET_TEMPLATE_EXPLORER': + case TemplateExplorerWizardAction.SET_WORKSPACE_TEMPLATE: return action.payload + case TemplateExplorerWizardAction.SET_WORKSPACE_TEMPLATE_WIZARD_STEP: + return action.payload + case TemplateExplorerWizardAction.SET_WORKSPACE_TEMPLATE_GROUP: + return action.payload + case TemplateExplorerWizardAction.SET_WORKSPACE_NAME: + return action.payload + case TemplateExplorerWizardAction.SET_DEFAULT_WORKSPACE_NAME: + return action.payload + case TemplateExplorerWizardAction.SET_TOP_LEFT_NAVIGATION_NAME: + return action.payload + case TemplateExplorerWizardAction.SET_INITIALIZE_AS_GIT_REPO: + return action.payload + case TemplateExplorerWizardAction.SET_WORKSPACE_GENERATED_WITH_AI: + return action.payload + case TemplateExplorerWizardAction.END_WORKSPACE_WIZARD: + return action.payload + case TemplateExplorerWizardAction.SET_SELECTED_TAG: { + return { ...state, selectedTag: action.payload } + } + case TemplateExplorerWizardAction.CLEAR_SELECTED_TAG: { + return { ...state, selectedTag: null } + } + default: + return state } } diff --git a/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx b/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx index dd50506618f..69026ec6127 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx @@ -1,6 +1,8 @@ import React from 'react' -import { TopCard, TopCardProps } from './topCard' +import { TopCard } from './topCard' +import { TopCardProps } from '../../types/template-explorer-types' import { TemplateExplorer } from './template-explorer' +import { TopCards } from './topCards' export interface TemplateExplorerBodyProps { topCards: TopCardProps[] @@ -10,15 +12,9 @@ export interface TemplateExplorerBodyProps { export function TemplateExplorerBody({ topCards, plugin }: TemplateExplorerBodyProps) { return (
-
- {/* {props.appState.genericModalState.title && props.appState.genericModalState.title} {props.appState.genericModalState.title} */} -
- {topCards.map((card) => ( - - ))} -
-
-
+ +
+
diff --git a/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx b/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx index b971473c77e..02f128cb22e 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx @@ -1,189 +1,152 @@ -import { CustomTooltip } from '@remix-ui/helper' -import { RemixUIGridCell, RemixUIGridSection, RemixUIGridView } from '@remix-ui/remix-ui-grid-view' -import { templates } from '@remix-ui/workspace' - import isElectron from 'is-electron' -import React, { useState, useMemo } from 'react' -import { metadata, templatesRepository } from '../utils/helpers' - -export interface TemplateItem { - value: string - displayName?: string - description?: string - tagList?: string[] - IsArtefact?: boolean - opts?: { - upgradeable?: string - mintable?: boolean - burnable?: boolean - pausable?: boolean - } - templateType?: any -} - -export interface TemplateCategory { - name: string - description?: string - hasOptions?: boolean - IsArtefact?: boolean - tooltip?: string - onClick?: () => void - onClickLabel?: string - items: TemplateItem[] -} - -export interface TemplateExplorerProps { - plugin: any -} +import React, { useContext } from 'react' +import { TemplateCategory, TemplateExplorerProps, TemplateItem } from '../../types/template-explorer-types' +import { TemplateExplorerContext } from '../../context/template-explorer-context' export function TemplateExplorer({ plugin }: TemplateExplorerProps) { - const [selectedTag, setSelectedTag] = useState(null) - const [recentBump, setRecentBump] = useState(0) - console.log('metadata', metadata) - console.log('templatesRepository', templatesRepository) + const { metadata, selectedTag, recentTemplates, dedupedTemplates, handleTagClick, clearFilter, addRecentTemplate, allTags } = useContext(TemplateExplorerContext) + + // console.log('metadata', metadata) + // console.log('templatesRepository', templatesRepository) // Get all unique tags from all templates - const allTags = useMemo((): string[] => { - const tags: string[] = [] + // const allTags = useMemo((): string[] => { + // const tags: string[] = [] + + // if (templateRepository && Array.isArray(templateRepository)) { + // templateRepository.forEach((template: any) => { + // if (template && template.items && Array.isArray(template.items)) { + // template.items.forEach((item: any) => { + // if (item && item.tagList && Array.isArray(item.tagList)) { + // item.tagList.forEach((tag: string) => { + // if (typeof tag === 'string' && !tags.includes(tag)) { + // tags.push(tag) + // } + // }) + // } + // }) + // } + // }) + // } - if (templatesRepository && Array.isArray(templatesRepository)) { - templatesRepository.forEach((template: any) => { - if (template && template.items && Array.isArray(template.items)) { - template.items.forEach((item: any) => { - if (item && item.tagList && Array.isArray(item.tagList)) { - item.tagList.forEach((tag: string) => { - if (typeof tag === 'string' && !tags.includes(tag)) { - tags.push(tag) - } - }) - } - }) - } - }) - } + // return tags.sort() + // }, []) - return tags.sort() - }, []) + // // Recent templates (before filteredTemplates so it can be referenced later) + // const recentTemplates = useMemo((): TemplateItem[] => { + // try { + // const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null + // const list: string[] = raw ? JSON.parse(raw) : [] + // const items: TemplateItem[] = [] + // if (Array.isArray(templateRepository)) { + // list.forEach((val) => { + // for (const group of templateRepository as any[]) { + // if (group && Array.isArray(group.items)) { + // const found = group.items.find((it: any) => it && it.value === val) + // if (found) { + // items.push(found) + // break + // } + // } + // } + // }) + // } + // //tag filter + // const filtered = selectedTag + // ? items.filter((it: any) => it && Array.isArray(it.tagList) && it.tagList.includes(selectedTag)) + // : items + // return filtered + // } catch (e) { + // return [] + // } + // }, [selectedTag, recentBump]) - // Recent templates (before filteredTemplates so it can be referenced later) - const recentTemplates = useMemo((): TemplateItem[] => { - try { - const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null - const list: string[] = raw ? JSON.parse(raw) : [] - const items: TemplateItem[] = [] - if (Array.isArray(templatesRepository)) { - list.forEach((val) => { - for (const group of templatesRepository as any[]) { - if (group && Array.isArray(group.items)) { - const found = group.items.find((it: any) => it && it.value === val) - if (found) { - items.push(found) - break - } - } - } - }) - } - //tag filter - const filtered = selectedTag - ? items.filter((it: any) => it && Array.isArray(it.tagList) && it.tagList.includes(selectedTag)) - : items - return filtered - } catch (e) { - return [] - } - }, [selectedTag, recentBump]) + // // Filter templates based on selected tag + // const filteredTemplates = useMemo((): TemplateCategory[] => { + // if (!selectedTag || !templateRepository || !Array.isArray(templateRepository)) { + // return templateRepository as TemplateCategory[] || [] + // } - // Filter templates based on selected tag - const filteredTemplates = useMemo((): TemplateCategory[] => { - if (!selectedTag || !templatesRepository || !Array.isArray(templatesRepository)) { - return templatesRepository as TemplateCategory[] || [] - } + // return (templateRepository as TemplateCategory[]).map((template: any) => ({ + // ...template, + // items: template.items.filter((item: any) => + // item && item.tagList && Array.isArray(item.tagList) && item.tagList.includes(selectedTag) + // ) + // })).filter((template: any) => template && template.items && template.items.length > 0) + // }, [selectedTag]) - return (templatesRepository as TemplateCategory[]).map((template: any) => ({ - ...template, - items: template.items.filter((item: any) => - item && item.tagList && Array.isArray(item.tagList) && item.tagList.includes(selectedTag) - ) - })).filter((template: any) => template && template.items && template.items.length > 0) - }, [selectedTag]) + // // Dedupe templates across the whole page and avoid showing ones already in recents + // const dedupedTemplates = useMemo((): TemplateCategory[] => { + // const recentSet = new Set((recentTemplates || []).map((t: any) => t && t.value)) + // const seen = new Set() + // const makeUniqueItems = (items: any[]) => { + // const unique: any[] = [] + // for (const it of items || []) { + // const val = it && it.value + // if (!val) continue + // if (recentSet.has(val)) continue + // if (seen.has(val)) continue + // seen.add(val) + // unique.push(it) + // } + // return unique + // } + // return (filteredTemplates || []).map((group: any) => ({ + // ...group, + // items: makeUniqueItems(group && group.items ? group.items : []) + // })).filter((g: any) => g && g.items && g.items.length > 0) + // }, [filteredTemplates, recentTemplates]) - // Dedupe templates across the whole page and avoid showing ones already in recents - const dedupedTemplates = useMemo((): TemplateCategory[] => { - const recentSet = new Set((recentTemplates || []).map((t: any) => t && t.value)) - const seen = new Set() - const makeUniqueItems = (items: any[]) => { - const unique: any[] = [] - for (const it of items || []) { - const val = it && it.value - if (!val) continue - if (recentSet.has(val)) continue - if (seen.has(val)) continue - seen.add(val) - unique.push(it) - } - return unique - } - return (filteredTemplates || []).map((group: any) => ({ - ...group, - items: makeUniqueItems(group && group.items ? group.items : []) - })).filter((g: any) => g && g.items && g.items.length > 0) - }, [filteredTemplates, recentTemplates]) + // const handleTagClick = (tag: string) => { + // setSelectedTag(selectedTag === tag ? null : tag) + // } - const handleTagClick = (tag: string) => { - setSelectedTag(selectedTag === tag ? null : tag) - } + // const clearFilter = () => { + // setSelectedTag(null) + // } - const clearFilter = () => { - setSelectedTag(null) - } + // const RECENT_KEY = 'remix.recentTemplates' - const RECENT_KEY = 'remix.recentTemplates' + // const addRecentTemplate = (templateValue: string) => { + // try { + // const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null + // const list: string[] = raw ? JSON.parse(raw) : [] + // const filtered = list.filter((v) => v !== templateValue) + // filtered.unshift(templateValue) + // const trimmed = filtered.slice(0, 4) + // if (typeof window !== 'undefined') window.localStorage.setItem(RECENT_KEY, JSON.stringify(trimmed)) + // setRecentBump((v) => v + 1) + // } catch (e) { - const addRecentTemplate = (templateValue: string) => { - try { - const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null - const list: string[] = raw ? JSON.parse(raw) : [] - const filtered = list.filter((v) => v !== templateValue) - filtered.unshift(templateValue) - const trimmed = filtered.slice(0, 4) - if (typeof window !== 'undefined') window.localStorage.setItem(RECENT_KEY, JSON.stringify(trimmed)) - setRecentBump((v) => v + 1) - } catch (e) { + // } + // } - } - } + const filterTheseTags = tag => tag !== 'Circom' && tag !== 'All' && tag !== 'Noir' && tag !== 'AI' return ( -
+
{/* Tag Filter Row */}
- Filter by tag: - - {allTags.map((tag: any) => ( - + ))} {selectedTag && ( - + )}
@@ -221,7 +184,7 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { flexDirection: 'column' }} onClick={() => { - addRecentTemplate(item.value) + addRecentTemplate(item) }} onMouseEnter={(e) => { e.currentTarget.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)' @@ -233,11 +196,12 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { }} >
-
{item.displayName || item.value}
@@ -262,7 +226,7 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { flexDirection: 'column' }}> {item.description && ( -

- {template.name} + {template.name.toUpperCase()} {template.description && ( @@ -371,7 +335,7 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { }} onClick={() => { console.log('Template selected:', item.value, item.opts) - addRecentTemplate(item.value) + addRecentTemplate(item) }} onMouseEnter={(e) => { e.currentTarget.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)' @@ -382,55 +346,33 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { e.currentTarget.style.transform = 'translateY(0)' }} > -

-
+
{item.displayName || item.value}
- {item.tagList && item.tagList.length > 0 && ( -
- {item.tagList.map((tag, tagIndex) => ( - - {tag} - - ))} -
- )}
- -
{item.description && ( -

{item.description}

)} {item.opts && Object.keys(item.opts).length > 0 && ( -
{item.opts.upgradeable && ( @@ -471,6 +413,22 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { )}
)} + + {item.tagList && item.tagList.length > 0 && ( +
+ {item.tagList.map((tag, tagIndex) => ( + + {tag} + + ))} +
+ )}
) diff --git a/libs/remix-ui/template-explorer-modal/src/components/topCard.tsx b/libs/remix-ui/template-explorer-modal/src/components/topCard.tsx index d502eb95dba..1ac0ea6d953 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/topCard.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/topCard.tsx @@ -1,29 +1,24 @@ import React from 'react' - -export interface TopCardProps { - title: string - description: string - icon: string - onClick: () => void - importWorkspace: boolean -} +import { TopCardProps } from '../../types/template-explorer-types' export function TopCard(props: TopCardProps) { return (
- {props.title.includes('AI') ? : } + {props.title.includes('AI') || props.description.includes('OpenZeppelin') ? : }

{props.title}

-

{props.description}

+

{props.description}

) diff --git a/libs/remix-ui/template-explorer-modal/src/components/topCards.tsx b/libs/remix-ui/template-explorer-modal/src/components/topCards.tsx new file mode 100644 index 00000000000..c5395dfb5f1 --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/components/topCards.tsx @@ -0,0 +1,110 @@ +import React from 'react' + +export function TopCards() { + return ( +
+
+
{}} + style={{ + borderRadius: '10px', + height: '76px', + width: '298px' + }} + onMouseEnter={(e) => { + e.currentTarget.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)' + e.currentTarget.style.transform = 'translateY(-2px)' + }} + onMouseLeave={(e) => { + e.currentTarget.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)' + e.currentTarget.style.transform = 'translateY(0)' + }} + > + + + + +

Create blank

+

Create an empty workspace

+
+
+
{}} + style={{ + borderRadius: '10px', + height: '76px', + width: '298px' + }} + onMouseEnter={(e) => { + e.currentTarget.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)' + e.currentTarget.style.transform = 'translateY(-2px)' + }} + onMouseLeave={(e) => { + e.currentTarget.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)' + e.currentTarget.style.transform = 'translateY(0)' + }} + > + + + + +

Create with AI

+

Generate a workspace with AI

+
+
+
{}} + style={{ + borderRadius: '10px', + height: '76px', + width: '298px' + }} + onMouseEnter={(e) => { + e.currentTarget.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)' + e.currentTarget.style.transform = 'translateY(-2px)' + }} + onMouseLeave={(e) => { + e.currentTarget.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)' + e.currentTarget.style.transform = 'translateY(0)' + }} + > + + + + +

Contract Wizard

+

Create a new contract with the OpenZeppelin Wizard

+
+
+
{}} + style={{ + borderRadius: '10px', + height: '76px', + width: '298px' + }} + onMouseEnter={(e) => { + e.currentTarget.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)' + e.currentTarget.style.transform = 'translateY(-2px)' + }} + onMouseLeave={(e) => { + e.currentTarget.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)' + e.currentTarget.style.transform = 'translateY(0)' + }} + > + + + + +

Import Project

+

Import an existing project

+
+
+
+
+ ) +} diff --git a/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.css b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.css index f5add1d6947..8955dc58351 100644 --- a/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.css +++ b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.css @@ -59,6 +59,13 @@ background-color: transparent; } +.template-explorer-modal-search-input { + background-image: url('search-icon.svg'); + background-position: 10px 8px; + background-repeat: no-repeat; + color: var(--bs-light); +} + .explora-topcard { cursor: pointer; } diff --git a/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx index af3a87362fa..855464b974f 100644 --- a/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx +++ b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx @@ -1,8 +1,12 @@ -import React from 'react' +import React, { useContext, useMemo, useReducer, useState } from 'react' import './remix-ui-template-explorer-modal.css' import { appActionTypes, AppState } from '@remix-ui/app' -import { TopCard, TopCardProps } from '../components/topCard' +import { TopCardProps } from '../../types/template-explorer-types' import { TemplateExplorerBody } from '../components/template-explorer-body' +import { TemplateCategory, TemplateItem } from '../../types/template-explorer-types' +import { metadata, templatesRepository } from '../utils/helpers' +import { TemplateExplorerContext, TemplateExplorerProvider } from '../../context/template-explorer-context' +import { initialState, templateExplorerReducer } from '../../reducers/template-explorer-reducer' export interface RemixUiTemplateExplorerModalProps { dispatch: any @@ -11,13 +15,6 @@ export interface RemixUiTemplateExplorerModalProps { } const topCards: TopCardProps[] = [ - { - title: 'Create blank', - description: 'Create an empty workspace', - icon: 'fa-solid fa-plus', - onClick: () => alert('Create blank'), - importWorkspace: false - }, { title: 'Create with AI', description: 'Generate a workspace with AI', @@ -25,31 +22,56 @@ const topCards: TopCardProps[] = [ onClick: () => alert('Create with AI'), importWorkspace: false }, + { + title: 'Create blank', + description: 'Create an empty workspace', + icon: 'fa-solid fa-plus', + onClick: () => alert('Create blank'), + importWorkspace: false + }, { title: 'Import Project', description: 'Import an existing project', icon: 'fas fa-upload', onClick: () => alert('Import Project'), importWorkspace: true + }, + { + title: 'Contract Wizard', + description: 'Create a new contract with the OpenZeppelin Wizard', + icon: 'assets/img/openzeppelin-logo.webp', + onClick: () => alert('Contract Wizard'), + importWorkspace: false } ] export function RemixUiTemplateExplorerModal (props: RemixUiTemplateExplorerModalProps) { + const { selectedTag, recentTemplates, filteredTemplates, dedupedTemplates, handleTagClick, clearFilter, addRecentTemplate, allTags } = useContext(TemplateExplorerContext) + const [state, dispatch] = useReducer(templateExplorerReducer, initialState) + + console.log('metadata', state.metadata) + console.log('templatesRepository', state.templatesRepository) + return ( -
-
-
- -
- -
- {props.appState.genericModalState.footer && props.appState.genericModalState.footer} + +
+
+
+
+ +
+ +
+ +
+ {props.appState.genericModalState.footer && props.appState.genericModalState.footer} +
-
-
+
+ ) } diff --git a/libs/remix-ui/template-explorer-modal/src/lib/search-icon.svg b/libs/remix-ui/template-explorer-modal/src/lib/search-icon.svg new file mode 100644 index 00000000000..d4bc50a2bbb --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/lib/search-icon.svg @@ -0,0 +1,18 @@ + diff --git a/libs/remix-ui/template-explorer-modal/src/utils/helpers.tsx b/libs/remix-ui/template-explorer-modal/src/utils/helpers.tsx index 178051b3a16..4c2eb2ada44 100644 --- a/libs/remix-ui/template-explorer-modal/src/utils/helpers.tsx +++ b/libs/remix-ui/template-explorer-modal/src/utils/helpers.tsx @@ -5,26 +5,20 @@ export const templatesRepository = [ name: "Generic", items: [ { value: "remixDefault", tagList: ["Solidity"], - // displayName: intl.formatMessage({ id: 'filePanel.basic' }), + displayName: 'Basic', description: 'The default project', - // templateType: TEMPLATE_METADATA['remixDefault'] }, { value: "blank", - // displayName: intl.formatMessage({ id: 'filePanel.blank' }), + displayName: 'Blank', IsArtefact: true, description: 'A blank project', - // templateType: TEMPLATE_METADATA['blank'] }, { value: "simpleEip7702", displayName: 'Simple EIP 7702', IsArtefact: true, description: 'Pectra upgrade allowing externally owned accounts (EOAs) to run contract code.', - // templateType: TEMPLATE_METADATA['simpleEip7702'] }, { value: "accountAbstraction", displayName: 'Account Abstraction', IsArtefact: true, description: 'A repo about ERC-4337 and EIP-7702', - // templateType: TEMPLATE_METADATA['accountAbstraction'] }, { value: 'remixAiTemplate', tagList: ['AI'], displayName: 'RemixAI Template Generation', IsArtefact: true, description: 'AI generated workspace. Workspace gets generated with a user prompt.', - // templateType: TEMPLATE_METADATA['remixAiTemplate'] }, { value: "introToEIP7702", displayName: 'Intro to EIP-7702', IsArtefact: true, description: 'A contract for demoing EIP-7702', - // templateType: TEMPLATE_METADATA['introToEIP7702'] }, ] }, @@ -37,7 +31,6 @@ export const templatesRepository = [ displayName: "ERC20", tagList: ["ERC20", "Solidity"], description: 'A customizable fungible token contract', - // templateType: TEMPLATE_METADATA['ozerc20'] }, { value: "ozerc20", @@ -47,7 +40,6 @@ export const templatesRepository = [ opts: { mintable: true }, - // templateType: TEMPLATE_METADATA['ozerc20'] }, { value: "ozerc20", @@ -58,7 +50,6 @@ export const templatesRepository = [ mintable: true, burnable: true }, - // templateType: TEMPLATE_METADATA['ozerc20'] }, { value: "ozerc20", @@ -69,14 +60,12 @@ export const templatesRepository = [ pausable: true }, tagList: ["ERC20", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc20'] }, { value: "ozerc721", displayName: "ERC721 (NFT)", tagList: ["ERC721", "Solidity"], description: 'A customizable non-fungible token (NFT) contract', - // templateType: TEMPLATE_METADATA['ozerc721'] }, { value: "ozerc721", @@ -86,7 +75,6 @@ export const templatesRepository = [ opts: { mintable: true }, - // templateType: TEMPLATE_METADATA['ozerc721'] }, { value: "ozerc721", @@ -97,7 +85,6 @@ export const templatesRepository = [ burnable: true }, tagList: ["ERC721", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc721'] }, { value: "ozerc721", @@ -108,14 +95,12 @@ export const templatesRepository = [ pausable: true }, tagList: ["ERC721", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc721'] }, { value: "ozerc1155", tagList: ["Solidity"], displayName: "ERC1155", description: 'A customizable multi token contract', - // templateType: TEMPLATE_METADATA['ozerc1155'] }, { value: "ozerc1155", @@ -125,7 +110,6 @@ export const templatesRepository = [ opts: { mintable: true }, - // templateType: TEMPLATE_METADATA['ozerc1155'] }, { value: "ozerc1155", @@ -136,7 +120,6 @@ export const templatesRepository = [ burnable: true }, tagList: ["ERC1155", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc1155'] }, { value: "ozerc1155", @@ -147,7 +130,6 @@ export const templatesRepository = [ mintable: true, pausable: true }, - // templateType: TEMPLATE_METADATA['ozerc1155'] } ] }, @@ -162,7 +144,6 @@ export const templatesRepository = [ upgradeable: 'uups' }, tagList: ["ERC20", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc20'] }, { value: "ozerc20", @@ -173,7 +154,6 @@ export const templatesRepository = [ mintable: true }, tagList: ["ERC20", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc20'] }, { value: "ozerc20", @@ -185,7 +165,6 @@ export const templatesRepository = [ burnable: true }, tagList: ["ERC20", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc20'] }, { value: "ozerc20", @@ -197,7 +176,6 @@ export const templatesRepository = [ pausable: true }, tagList: ["ERC20", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc20'] }, { value: "ozerc721", @@ -207,7 +185,6 @@ export const templatesRepository = [ upgradeable: 'uups' }, tagList: ["ERC721", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc721'] }, { value: "ozerc721", @@ -218,7 +195,6 @@ export const templatesRepository = [ mintable: true }, tagList: ["ERC721", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc721'] }, { value: "ozerc721", @@ -230,7 +206,6 @@ export const templatesRepository = [ burnable: true }, tagList: ["ERC721", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc721'] }, { value: "ozerc721", @@ -242,7 +217,6 @@ export const templatesRepository = [ pausable: true }, tagList: ["ERC721", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc721'] }, { value: "ozerc1155", @@ -252,7 +226,6 @@ export const templatesRepository = [ upgradeable: 'uups' }, tagList: ["ERC1155", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc1155'] }, { value: "ozerc1155", @@ -263,7 +236,6 @@ export const templatesRepository = [ mintable: true }, tagList: ["ERC1155", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc1155'] }, { value: "ozerc1155", @@ -275,7 +247,6 @@ export const templatesRepository = [ burnable: true }, tagList: ["ERC1155", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc1155'] }, { value: "ozerc1155", @@ -287,7 +258,6 @@ export const templatesRepository = [ pausable: true }, tagList: ["ERC1155", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc1155'] }, { value: "ozerc1155", @@ -300,7 +270,6 @@ export const templatesRepository = [ pausable: true }, tagList: ["ERC1155", "Solidity"], - // templateType: TEMPLATE_METADATA['ozerc1155'] } ] }, @@ -367,45 +336,43 @@ export const templatesRepository = [ name: "0xProject", items: [ { value: "zeroxErc20", displayName: "ERC20", tagList: ["ERC20", "Solidity"], description: "A fungible token contract by 0xProject", - // templateType: TEMPLATE_METADATA['zeroxErc20'] } ] }, { name: "Gnosis Safe", items: [ - { value: "gnosisSafeMultisig", tagList: ["Solidity"], // displayName: intl.formatMessage({ id: 'filePanel.multiSigWallet' }), + { value: "gnosisSafeMultisig", tagList: ["Solidity"], + displayName: 'MultiSig Wallet', description: 'Deploy or customize the Gnosis Safe MultiSig Wallet', - // templateType: TEMPLATE_METADATA['gnosisSafeMultisig'] } ] }, { name: "Circom ZKP", items: [ - { value: "semaphore", tagList: ["ZKP", "Circom"], // displayName: intl.formatMessage({ id: 'filePanel.semaphore' }), + { value: "semaphore", tagList: ["ZKP", "Circom"], + displayName: 'Semaphore', description: 'Semaphore protocol for casting a message as a provable group member', - // templateType: TEMPLATE_METADATA['semaphore'] }, - { value: "hashchecker", tagList: ["ZKP", "Circom"], // displayName: intl.formatMessage({ id: 'filePanel.hashchecker' }), + { value: "hashchecker", tagList: ["ZKP", "Circom"], + displayName: 'Hash Checker', description: 'Hash checker Circom circuit', - // templateType: TEMPLATE_METADATA['hashchecker'] }, { value: "rln", tagList: ["ZKP", "Circom"], - //displayName: intl.formatMessage({ id: 'filePanel.rln' }), + displayName: 'Rate-Limiting Nullifier', description: 'Rate Limiting Nullifier Circom circuit', - // templateType: TEMPLATE_METADATA['rln'] } ] }, { name: "Noir ZKP", items: [ - { value: "multNr", tagList: ["ZKP", "Noir"], // displayName: intl.formatMessage({ id: 'filePanel.multNr' }), + { value: "multNr", tagList: ["ZKP", "Noir"], + displayName: 'Simple Multiplier', description: 'A simple multiplier circuit', - // templateType: TEMPLATE_METADATA['multNr'] - } - // { value: "stealthDropNr", tagList: ["ZKP", "Noir"], displayName: intl.formatMessage({ id: 'filePanel.stealthDropNr' }),} + }, + { value: "stealthDropNr", tagList: ["ZKP", "Noir"], displayName: 'Stealth Drop',} ] }, { @@ -414,9 +381,9 @@ export const templatesRepository = [ { value: "sindriScripts", tagList: ["ZKP"], - // displayName: intl.formatMessage({ id: 'filePanel.addscriptsindri' }), + displayName: 'Add Sindri ZK scripts', description: 'Use the Sindri API to compile and generate proofs', - // templateType: TEMPLATE_METADATA['sindriScripts'] + }, ], }, @@ -424,21 +391,18 @@ export const templatesRepository = [ name: "Uniswap V4", items: [ { value: "uniswapV4Template", - // displayName: intl.formatMessage({ id: 'filePanel.uniswapV4Template' }), + displayName: 'Uniswap v4 Template', description: 'Use a Uniswap hook', - // templateType: TEMPLATE_METADATA['uniswapV4Template'] }, { value: "breakthroughLabsUniswapv4Hooks", - // displayName: intl.formatMessage({ id: 'filePanel.breakthroughLabsUniswapv4Hooks' }), + displayName: 'Breakthrough-Labs Hooks', description: 'Use a Uniswap hook developed by Breakthrough Labs', - // templateType: TEMPLATE_METADATA['breakthroughLabsUniswapv4Hooks'] }, { value: "uniswapV4HookBookMultiSigSwapHook", - // displayName: intl.formatMessage({ id: 'filePanel.uniswapV4HookBookMultiSigSwapHook' }), + displayName: 'HookBook MultiSigSwapHook', description: 'Use a MultiSigSwapHook developed by Breakthrough Labs', - // templateType: TEMPLATE_METADATA['uniswapV4HookBookMultiSigSwapHook'] } ] }, @@ -448,15 +412,13 @@ export const templatesRepository = [ { value: "contractCreate2Factory", tagList: ["Solidity"], - // displayName: intl.formatMessage({ id: 'filePanel.addcreate2solidityfactory' }), + displayName: 'Add Create2 Solidity factory', description: 'Factory for deploying a contract using the CREATE2 opcode', - // templateType: TEMPLATE_METADATA['contractCreate2Factory'] }, { value: "contractDeployerScripts", - // displayName: intl.formatMessage({ id: 'filePanel.addscriptdeployer' }), + displayName: 'Add contract deployer scripts', description: 'Script for deploying a contract using the CREATE2 opcode', - // templateType: TEMPLATE_METADATA['contractDeployerScripts'] } ] }, @@ -465,9 +427,8 @@ export const templatesRepository = [ items: [ { value: "etherscanScripts", - // displayName: intl.formatMessage({ id: 'filePanel.addscriptetherscan' }), + displayName: 'Add Etherscan scripts', description: 'Script for verifying a Contract in Etherscan', - // templateType: TEMPLATE_METADATA['etherscanScripts'] }, ], }, @@ -475,20 +436,17 @@ export const templatesRepository = [ name: 'GitHub Actions', items: [ { value: "runJsTestAction", - // displayName: intl.formatMessage({ id: 'filePanel.tssoltestghaction' }), + displayName: 'Mocha Chai Test Workflow', description: 'A Mocha Chai test workflow in a GitHub CI', - // templateType: TEMPLATE_METADATA['runJsTestAction'] }, { value: "runSolidityUnittestingAction", - // displayName: intl.formatMessage({ id: 'filePanel.solghaction' }), + displayName: 'Solidity Test Workflow', description: 'Run a Solidity unit test workflow in a GitHub CI', - // templateType: TEMPLATE_METADATA['runSolidityUnittestingAction'] }, { value: "runSlitherAction", - // displayName: intl.formatMessage({ id: 'filePanel.slitherghaction' }), + displayName: 'Slither Workflow', description: 'Run a Slither security analysis in a GitHub CI', - // templateType: TEMPLATE_METADATA['runSlitherAction'] } ], IsArtefact: true diff --git a/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts b/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts index db7ee583943..a54ce0f831a 100644 --- a/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts +++ b/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts @@ -7,11 +7,108 @@ export interface TemplateExplorerWizardState { defaultWorkspaceName: string topLeftNagivationName: string initializeAsGitRepo: boolean + workspaceGeneratedWithAi: boolean + searchTerm: string + metadata: MetadataType + templateRepository: TemplateCategory[] + selectedTag: string | null +} + +export interface TemplateExplorerContextType { + templateRepository: TemplateCategory[] + metadata: any[] + selectedTag: string | null + recentTemplates: TemplateItem[] + filteredTemplates: TemplateCategory[] + dedupedTemplates: TemplateCategory[] + handleTagClick: (tag: string) => void + clearFilter: () => void + addRecentTemplate: (template: TemplateItem) => void + RECENT_KEY: string + allTags: string[] } export enum TemplateExplorerWizardSteps { SELECT_TEMPLATE = 'SELECT_TEMPLATE', GENERATE_TEMPLATE = 'GENERATE_TEMPLATE', MODIFY_WORKSPACE = 'MODIFY_WORKSPACE', - REVIEW_WORKSPACE = 'REVIEW_WORKSPACE' + REVIEW_WORKSPACE = 'REVIEW_WORKSPACE', + IMPORT_WORKSPACE = 'IMPORT_WORKSPACE', + FINALIZE_WORKSPACE_CREATION = 'FINALIZE_WORKSPACE_CREATION', + ABORT_WORKSPACE_CREATION = 'ABORT_WORKSPACE_CREATION', + BACK_ONE_STEP = 'BACK_ONE_STEP' +} + +export enum TemplateExplorerWizardAction { + SET_WORKSPACE_TEMPLATE = 'SET_WORKSPACE_TEMPLATE', + SET_WORKSPACE_TEMPLATE_WIZARD_STEP = 'SET_WORKSPACE_TEMPLATE_WIZARD_STEP', + SET_WORKSPACE_TEMPLATE_GROUP = 'SET_WORKSPACE_TEMPLATE_GROUP', + SET_WORKSPACE_NAME = 'SET_WORKSPACE_NAME', + SET_DEFAULT_WORKSPACE_NAME = 'SET_DEFAULT_WORKSPACE_NAME', + SET_TOP_LEFT_NAVIGATION_NAME = 'SET_TOP_LEFT_NAVIGATION_NAME', + SET_INITIALIZE_AS_GIT_REPO = 'SET_INITIALIZE_AS_GIT_REPO', + SET_WORKSPACE_GENERATED_WITH_AI = 'SET_WORKSPACE_GENERATED_WITH_AI', + END_WORKSPACE_WIZARD = 'END_WORKSPACE_WIZARD', + SET_RECENT_BUMP = 'SET_RECENT_BUMP', + SET_SELECTED_TAG = 'SET_SELECTED_TAG', + CLEAR_SELECTED_TAG = 'CLEAR_SELECTED_TAG', + SET_METADATA = 'SET_METADATA', + SET_TEMPLATE_REPOSITORY = 'SET_TEMPLATE_REPOSITORY' +} + +export interface TemplateItem { + value: string + displayName?: string + description?: string + tagList?: string[] + IsArtefact?: boolean + opts?: { + upgradeable?: string + mintable?: boolean + burnable?: boolean + pausable?: boolean + } + templateType?: any +} + +export interface TemplateCategory { + name: string + description?: string + hasOptions?: boolean + IsArtefact?: boolean + tooltip?: string + onClick?: () => void + onClickLabel?: string + items: TemplateItem[] +} + +export type MetadataType = Record + +export type MetadataItem = +| { + type: 'git'; + url: string; + branch: string; + forceCreateNewWorkspace: boolean; + } +| { + type: 'plugin'; + name: string; + endpoint: string; + params: string[]; + forceCreateNewWorkspace?: boolean; + desktopCompatible?: boolean; + disabled?: boolean; + } + +export interface TemplateExplorerProps { + plugin: any +} + +export interface TopCardProps { + title: string + description: string + icon: string + onClick: () => void + importWorkspace: boolean } From a393474495f7d993b602398a3c73513bdd5b3993 Mon Sep 17 00:00:00 2001 From: ci-bot Date: Tue, 23 Sep 2025 23:07:44 +0100 Subject: [PATCH 07/15] fix search to filter and filter by tag. fix order of components --- apps/remix-ide/src/app.ts | 6 +- .../plugins/remix-template-explorer-modal.tsx | 23 +++---- .../app/src/lib/remix-app/remix-app.tsx | 5 +- .../context/template-explorer-context.tsx | 60 ++++++++++++----- .../reducers/template-explorer-reducer.tsx | 28 ++++++-- .../src/components/template-explorer-body.tsx | 36 ++++++++-- .../src/components/template-explorer.tsx | 66 ++++++------------- .../lib/remix-ui-template-explorer-modal.tsx | 62 ++++------------- .../src/utils/helpers.tsx | 2 +- .../types/template-explorer-types.ts | 30 +++++---- 10 files changed, 167 insertions(+), 151 deletions(-) diff --git a/apps/remix-ide/src/app.ts b/apps/remix-ide/src/app.ts index 03dc8c9d25b..d42977493d0 100644 --- a/apps/remix-ide/src/app.ts +++ b/apps/remix-ide/src/app.ts @@ -269,6 +269,7 @@ class AppComponent { this.gistHandler = new GistHandler() // ----------------- theme service --------------------------------- this.themeModule = new ThemeModule() + this.templateExplorerModal = new TemplateExplorerModalPlugin(this.themeModule) // ----------------- locale service --------------------------------- this.localeModule = new LocaleModule() Registry.getInstance().put({ api: this.themeModule, name: 'themeModule' }) @@ -403,7 +404,7 @@ class AppComponent { const templateSelection = new TemplatesSelectionPlugin() - const templateExplorerModal = new TemplateExplorerModalPlugin() + const templateExplorerModal = this.templateExplorerModal const walletConnect = new WalletConnect() @@ -460,10 +461,10 @@ class AppComponent { pluginStateLogger, matomo, templateSelection, - templateExplorerModal, scriptRunnerUI, remixAI, remixAiAssistant, + templateExplorerModal, walletConnect ]) @@ -616,6 +617,7 @@ class AppComponent { await this.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs']) await this.appManager.activatePlugin(['topbar']) await this.appManager.activatePlugin(['statusBar']) + // await this.appManager.activatePlugin(['remix-template-explorer-modal']) await this.appManager.activatePlugin(['bottomBar']) await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately await this.appManager.activatePlugin(['pinnedPanel']) diff --git a/apps/remix-ide/src/app/plugins/remix-template-explorer-modal.tsx b/apps/remix-ide/src/app/plugins/remix-template-explorer-modal.tsx index afa0638d94d..65015ac2200 100644 --- a/apps/remix-ide/src/app/plugins/remix-template-explorer-modal.tsx +++ b/apps/remix-ide/src/app/plugins/remix-template-explorer-modal.tsx @@ -4,7 +4,8 @@ import { AppAction, AppState } from '@remix-ui/app' import { PluginViewWrapper } from '@remix-ui/helper' import { Plugin } from '@remixproject/engine' import { EventEmitter } from 'events' -import { RemixUiTemplateExplorerModal, RemixUiTemplateExplorerModalProps } from 'libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal' +import { ThemeModule } from '../tabs/theme-module' +import { TemplateExplorerProvider } from 'libs/remix-ui/template-explorer-modal/context/template-explorer-context' const pluginProfile = { name: 'remix-template-explorer-modal', @@ -18,16 +19,20 @@ export class TemplateExplorerModalPlugin extends Plugin { dispatch: React.Dispatch = () => { } event: any appStateDispatch: any - constructor() { + theme: any = null + constructor(theme: ThemeModule) { super(pluginProfile) this.element = document.createElement('div') - this.element.setAttribute('id', 'remix-template-explorer-modal') + this.element.setAttribute('id', 'template-explorer-modal') this.dispatch = () => { } this.event = new EventEmitter() + this.theme = theme } async onActivation(): Promise { - + this.on('theme', 'themeChanged', (theme: any) => { + this.theme = theme + }) } onDeactivation(): void { @@ -53,17 +58,13 @@ export class TemplateExplorerModalPlugin extends Plugin { renderComponent(): void { this.dispatch({ - element: this.element, + plugins: this, }) } - updateComponent(state: RemixUiTemplateExplorerModalProps, appState: AppState) { + updateComponent() { return ( - + ) } } diff --git a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx index 499e5c83bce..42acdd1e046 100644 --- a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx @@ -16,6 +16,7 @@ import { appInitialState } from './state/app' import isElectron from 'is-electron' import { desktopConnectionType } from '@remix-api' import { RemixUiTemplateExplorerModal } from 'libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal' +import { TemplateExplorerProvider } from 'libs/remix-ui/template-explorer-modal/context/template-explorer-context' declare global { interface Window { @@ -233,7 +234,9 @@ const RemixApp = (props: IRemixAppUi) => {
- {appState.genericModalState.showModal && } + {appState.genericModalState.showModal && + + } diff --git a/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx b/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx index 030148e3ef4..60e15d39e6b 100644 --- a/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx +++ b/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx @@ -1,25 +1,36 @@ +/* eslint-disable @nrwl/nx/enforce-module-boundaries */ import React, { createContext, useContext, useEffect, useMemo, useReducer, useState } from 'react' import { TemplateCategory, TemplateExplorerContextType, TemplateExplorerWizardAction, TemplateItem } from '../types/template-explorer-types' import { initialState, templateExplorerReducer } from '../reducers/template-explorer-reducer' import { metadata, templatesRepository } from '../src/utils/helpers' import { AppContext } from '@remix-ui/app' +import { TemplateExplorerModalPlugin } from 'apps/remix-ide/src/app/plugins/remix-template-explorer-modal' +import { RemixUiTemplateExplorerModal } from '@remix-ui/template-explorer-modal' export const TemplateExplorerContext = createContext({} as any) -export const TemplateExplorerProvider = ({ children }: { children: React.ReactNode }) => { +export const TemplateExplorerProvider = (props: { plugin: TemplateExplorerModalPlugin }) => { // const [templateRepository, setTemplateRepository] = useState([]) // const [metadata, setMetadata] = useState([]) // const [selectedTag, setSelectedTag] = useState(null) // const [recentBump, setRecentBump] = useState(0) const [state, dispatch] = useReducer(templateExplorerReducer, initialState) const appContext = useContext(AppContext) + const { plugin } = props useEffect(() => { - dispatch({ type: TemplateExplorerWizardAction.SET_METADATA, payload: metadata }) dispatch({ type: TemplateExplorerWizardAction.SET_TEMPLATE_REPOSITORY, payload: templatesRepository }) + }, []) + useEffect(() => { + dispatch({ type: TemplateExplorerWizardAction.SET_METADATA, payload: metadata }) }, []) + const setSearchTerm = (term: string) => { + console.log('setSearchTerm', { term, state }) + dispatch({ type: TemplateExplorerWizardAction.SET_SEARCH_TERM, payload: term }) + } + const allTags = useMemo((): string[] => { const tags: string[] = [] @@ -42,7 +53,6 @@ export const TemplateExplorerProvider = ({ children }: { children: React.ReactNo return tags.sort() }, []) - // Recent templates (before filteredTemplates so it can be referenced later) const recentTemplates = useMemo((): TemplateItem[] => { try { const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null @@ -71,21 +81,33 @@ export const TemplateExplorerProvider = ({ children }: { children: React.ReactNo } }, [state.selectedTag, state.recentBump]) - // Filter templates based on selected tag const filteredTemplates = useMemo((): TemplateCategory[] => { - if (!state.selectedTag || !state.templateRepository || !Array.isArray(state.templateRepository)) { - return state.templateRepository as TemplateCategory[] || [] - } + const repo = (state.templateRepository as TemplateCategory[]) || [] + if (!Array.isArray(repo)) return [] + + const searchTerm = (state.searchTerm || '').trim().toLowerCase() + const selectedTag = state.selectedTag + + return repo + .map((template: TemplateCategory) => ({ + ...template, + items: (template.items || []).filter((item: TemplateItem) => { + // Filter by search term + const matchesSearch = !searchTerm || + (item.displayName || item.value || '').toLowerCase().includes(searchTerm) - return (state.templateRepository as TemplateCategory[]).map((template: any) => ({ - ...template, - items: template.items.filter((item: any) => - item && item.tagList && Array.isArray(item.tagList) && item.tagList.includes(state.selectedTag) + // Filter by selected tag + const matchesTag = !selectedTag || + (item.tagList && item.tagList.includes(selectedTag)) + + return matchesSearch && matchesTag + }) + })) + .filter((template: TemplateCategory) => + template && template.items && template.items.length > 0 ) - })).filter((template: any) => template && template.items && template.items.length > 0) - }, [state.selectedTag]) + }, [state.selectedTag, state.searchTerm, state.templateRepository]) - // Dedupe templates across the whole page and avoid showing ones already in recents const dedupedTemplates = useMemo((): TemplateCategory[] => { const recentSet = new Set((recentTemplates || []).map((t: any) => t && t.value)) const seen = new Set() @@ -131,9 +153,15 @@ export const TemplateExplorerProvider = ({ children }: { children: React.ReactNo } } + const contextValue = { templateRepository: state.templateRepository, metadata: state.metadata, selectedTag: state.selectedTag, recentTemplates, filteredTemplates, dedupedTemplates, handleTagClick, clearFilter, addRecentTemplate, RECENT_KEY, allTags, plugin, setSearchTerm } + return ( - - {children} + + ) } diff --git a/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx b/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx index 8f4e2ad5518..e962dee9cb2 100644 --- a/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx +++ b/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx @@ -1,9 +1,8 @@ import React from 'react' -import { MetadataType, TemplateExplorerWizardAction, TemplateExplorerWizardState, TemplateExplorerWizardSteps } from '../types/template-explorer-types' +import { MetadataType, TemplateExplorerWizardAction, TemplateExplorerWizardState, TemplateRepository } from '../types/template-explorer-types' import { metadata, templatesRepository } from '../src/utils/helpers' export const initialState: TemplateExplorerWizardState = { - steps: TemplateExplorerWizardSteps.SELECT_TEMPLATE, workspaceTemplateChosen: '', workspaceTemplateGroupChosen: '', workspaceName: '', @@ -13,15 +12,18 @@ export const initialState: TemplateExplorerWizardState = { workspaceGeneratedWithAi: false, searchTerm: '', metadata: metadata as MetadataType, - templateRepository: templatesRepository, - selectedTag: null + templateRepository: templatesRepository as TemplateRepository || [], + selectedTag: null, + setSearchTerm: (term: string) => {} } export const templateExplorerReducer = (state: TemplateExplorerWizardState, action: any) => { switch (action.type) { - case TemplateExplorerWizardAction.SET_WORKSPACE_TEMPLATE: - return action.payload - case TemplateExplorerWizardAction.SET_WORKSPACE_TEMPLATE_WIZARD_STEP: + case TemplateExplorerWizardAction.SET_TEMPLATE_REPOSITORY: + return { ...state, templateRepository: action.payload } + case TemplateExplorerWizardAction.SET_METADATA: + return { ...state, metadata: action.payload } + case TemplateExplorerWizardAction.SELECT_TEMPLATE: return action.payload case TemplateExplorerWizardAction.SET_WORKSPACE_TEMPLATE_GROUP: return action.payload @@ -43,7 +45,19 @@ export const templateExplorerReducer = (state: TemplateExplorerWizardState, acti case TemplateExplorerWizardAction.CLEAR_SELECTED_TAG: { return { ...state, selectedTag: null } } + case TemplateExplorerWizardAction.SET_SEARCH_TERM: { + return { ...state, searchTerm: action.payload } + } default: return state } } + +function doTemplateSearch (searchTerm: string, repo: TemplateRepository) { + if (!searchTerm) return repo + return repo.filter(template => template.name.toLowerCase().includes(searchTerm.toLowerCase())) + .map(template => ({ + ...template, + items: template.items.filter(item => item.displayName.toLowerCase().includes(searchTerm.toLowerCase())) + })) +} diff --git a/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx b/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx index 69026ec6127..d0c287079e5 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx @@ -1,21 +1,49 @@ -import React from 'react' +import React, { useContext } from 'react' import { TopCard } from './topCard' import { TopCardProps } from '../../types/template-explorer-types' import { TemplateExplorer } from './template-explorer' import { TopCards } from './topCards' +import { TemplateExplorerContext } from '../../context/template-explorer-context' export interface TemplateExplorerBodyProps { - topCards: TopCardProps[] plugin: any } -export function TemplateExplorerBody({ topCards, plugin }: TemplateExplorerBodyProps) { +export function TemplateExplorerBody({ plugin }: TemplateExplorerBodyProps) { + const { selectedTag, allTags, handleTagClick, clearFilter } = useContext(TemplateExplorerContext) + + const filterTheseTags = tag => tag !== 'Circom' && tag !== 'All' && tag !== 'Noir' && tag !== 'AI' return (
- + {/* Tag Filter Row */} +
+
+ + {allTags?.filter(filterTheseTags)?.reverse()?.map((tag: any) => ( + handleTagClick(tag as any)} + > + {tag as any} + + ))} + {selectedTag && ( + + + Clear filter + + + )} +
+
+
) diff --git a/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx b/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx index 02f128cb22e..1db82736d94 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx @@ -1,11 +1,11 @@ import isElectron from 'is-electron' -import React, { useContext } from 'react' +import React, { useContext, useEffect } from 'react' import { TemplateCategory, TemplateExplorerProps, TemplateItem } from '../../types/template-explorer-types' import { TemplateExplorerContext } from '../../context/template-explorer-context' -export function TemplateExplorer({ plugin }: TemplateExplorerProps) { +export function TemplateExplorer() { - const { metadata, selectedTag, recentTemplates, dedupedTemplates, handleTagClick, clearFilter, addRecentTemplate, allTags } = useContext(TemplateExplorerContext) + const { metadata, recentTemplates, dedupedTemplates, addRecentTemplate, plugin } = useContext(TemplateExplorerContext) // console.log('metadata', metadata) // console.log('templatesRepository', templatesRepository) @@ -122,38 +122,11 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { // } // } - const filterTheseTags = tag => tag !== 'Circom' && tag !== 'All' && tag !== 'Noir' && tag !== 'AI' - return ( -
- {/* Tag Filter Row */} -
-
- - {allTags.filter(filterTheseTags).reverse().map((tag: any) => ( - handleTagClick(tag as any)} - > - {tag as any} - - ))} - {selectedTag && ( - - - Clear filter - - - )} -
-
+
{/* Recently Used Section */} - {recentTemplates && recentTemplates.length > 0 && ( + {/* {recentTemplates && recentTemplates?.length > 0 && (

- {recentTemplates.map((item: TemplateItem, itemIndex) => { + {recentTemplates?.map((item: TemplateItem, itemIndex) => { item.templateType = metadata[item.value] if (item.templateType && item.templateType.disabled === true) return null if (item.templateType && item.templateType.desktopCompatible === false && isElectron()) return null @@ -201,7 +174,7 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { fontWeight: '600', margin: 0, lineHeight: '1.2', - color: '#1B1D24' + color: plugin?.theme?.currentTheme().name === 'Light' ? '#1B1D24' : '#FFF' }}> {item.displayName || item.value}

@@ -288,21 +261,21 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { })}
- )} + )} */} - {dedupedTemplates.map((template: TemplateCategory, templateIndex) => ( + {dedupedTemplates?.map((template: TemplateCategory, templateIndex) => (
-

{template.name.toUpperCase()}

{template.description && ( -

+

{template.description}

)} @@ -346,26 +319,25 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { e.currentTarget.style.transform = 'translateY(0)' }} > -
+
{item.displayName || item.value}
-
{item.description && ( -

{item.description}

@@ -415,12 +387,12 @@ export function TemplateExplorer({ plugin }: TemplateExplorerProps) { )} {item.tagList && item.tagList.length > 0 && ( -
+
{item.tagList.map((tag, tagIndex) => ( - diff --git a/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx index 855464b974f..c169b2de0e1 100644 --- a/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx +++ b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx @@ -1,12 +1,8 @@ -import React, { useContext, useMemo, useReducer, useState } from 'react' +import React, { useContext } from 'react' import './remix-ui-template-explorer-modal.css' import { appActionTypes, AppState } from '@remix-ui/app' -import { TopCardProps } from '../../types/template-explorer-types' import { TemplateExplorerBody } from '../components/template-explorer-body' -import { TemplateCategory, TemplateItem } from '../../types/template-explorer-types' -import { metadata, templatesRepository } from '../utils/helpers' -import { TemplateExplorerContext, TemplateExplorerProvider } from '../../context/template-explorer-context' -import { initialState, templateExplorerReducer } from '../../reducers/template-explorer-reducer' +import { TemplateExplorerContext } from '../../context/template-explorer-context' export interface RemixUiTemplateExplorerModalProps { dispatch: any @@ -14,64 +10,34 @@ export interface RemixUiTemplateExplorerModalProps { plugin: any } -const topCards: TopCardProps[] = [ - { - title: 'Create with AI', - description: 'Generate a workspace with AI', - icon: 'assets/img/remixai-logoDefault.webp', - onClick: () => alert('Create with AI'), - importWorkspace: false - }, - { - title: 'Create blank', - description: 'Create an empty workspace', - icon: 'fa-solid fa-plus', - onClick: () => alert('Create blank'), - importWorkspace: false - }, - { - title: 'Import Project', - description: 'Import an existing project', - icon: 'fas fa-upload', - onClick: () => alert('Import Project'), - importWorkspace: true - }, - { - title: 'Contract Wizard', - description: 'Create a new contract with the OpenZeppelin Wizard', - icon: 'assets/img/openzeppelin-logo.webp', - onClick: () => alert('Contract Wizard'), - importWorkspace: false - } - -] - export function RemixUiTemplateExplorerModal (props: RemixUiTemplateExplorerModalProps) { - const { selectedTag, recentTemplates, filteredTemplates, dedupedTemplates, handleTagClick, clearFilter, addRecentTemplate, allTags } = useContext(TemplateExplorerContext) - const [state, dispatch] = useReducer(templateExplorerReducer, initialState) - - console.log('metadata', state.metadata) - console.log('templatesRepository', state.templatesRepository) + const { plugin, setSearchTerm } = useContext(TemplateExplorerContext) return ( - +
- + setSearchTerm(e.target.value)} + />
- +
{props.appState.genericModalState.footer && props.appState.genericModalState.footer}
- +
) } diff --git a/libs/remix-ui/template-explorer-modal/src/utils/helpers.tsx b/libs/remix-ui/template-explorer-modal/src/utils/helpers.tsx index 4c2eb2ada44..cc7e4ceb98e 100644 --- a/libs/remix-ui/template-explorer-modal/src/utils/helpers.tsx +++ b/libs/remix-ui/template-explorer-modal/src/utils/helpers.tsx @@ -372,7 +372,7 @@ export const templatesRepository = [ displayName: 'Simple Multiplier', description: 'A simple multiplier circuit', }, - { value: "stealthDropNr", tagList: ["ZKP", "Noir"], displayName: 'Stealth Drop',} + { value: "stealthDropNr", tagList: ["ZKP", "Noir"], displayName: 'Stealth Drop' } ] }, { diff --git a/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts b/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts index a54ce0f831a..afeb2d2b92d 100644 --- a/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts +++ b/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts @@ -1,6 +1,5 @@ export interface TemplateExplorerWizardState { - steps: TemplateExplorerWizardSteps workspaceTemplateChosen: string workspaceTemplateGroupChosen: string workspaceName: string @@ -12,15 +11,18 @@ export interface TemplateExplorerWizardState { metadata: MetadataType templateRepository: TemplateCategory[] selectedTag: string | null + setSearchTerm: (term: string) => void } export interface TemplateExplorerContextType { + plugin: any templateRepository: TemplateCategory[] metadata: any[] selectedTag: string | null recentTemplates: TemplateItem[] filteredTemplates: TemplateCategory[] dedupedTemplates: TemplateCategory[] + setSearchTerm: (term: string) => void handleTagClick: (tag: string) => void clearFilter: () => void addRecentTemplate: (template: TemplateItem) => void @@ -28,17 +30,6 @@ export interface TemplateExplorerContextType { allTags: string[] } -export enum TemplateExplorerWizardSteps { - SELECT_TEMPLATE = 'SELECT_TEMPLATE', - GENERATE_TEMPLATE = 'GENERATE_TEMPLATE', - MODIFY_WORKSPACE = 'MODIFY_WORKSPACE', - REVIEW_WORKSPACE = 'REVIEW_WORKSPACE', - IMPORT_WORKSPACE = 'IMPORT_WORKSPACE', - FINALIZE_WORKSPACE_CREATION = 'FINALIZE_WORKSPACE_CREATION', - ABORT_WORKSPACE_CREATION = 'ABORT_WORKSPACE_CREATION', - BACK_ONE_STEP = 'BACK_ONE_STEP' -} - export enum TemplateExplorerWizardAction { SET_WORKSPACE_TEMPLATE = 'SET_WORKSPACE_TEMPLATE', SET_WORKSPACE_TEMPLATE_WIZARD_STEP = 'SET_WORKSPACE_TEMPLATE_WIZARD_STEP', @@ -53,7 +44,16 @@ export enum TemplateExplorerWizardAction { SET_SELECTED_TAG = 'SET_SELECTED_TAG', CLEAR_SELECTED_TAG = 'CLEAR_SELECTED_TAG', SET_METADATA = 'SET_METADATA', - SET_TEMPLATE_REPOSITORY = 'SET_TEMPLATE_REPOSITORY' + SET_TEMPLATE_REPOSITORY = 'SET_TEMPLATE_REPOSITORY', + SELECT_TEMPLATE = 'SELECT_TEMPLATE', + GENERATE_TEMPLATE = 'GENERATE_TEMPLATE', + MODIFY_WORKSPACE = 'MODIFY_WORKSPACE', + REVIEW_WORKSPACE = 'REVIEW_WORKSPACE', + IMPORT_WORKSPACE = 'IMPORT_WORKSPACE', + FINALIZE_WORKSPACE_CREATION = 'FINALIZE_WORKSPACE_CREATION', + ABORT_WORKSPACE_CREATION = 'ABORT_WORKSPACE_CREATION', + BACK_ONE_STEP = 'BACK_ONE_STEP', + SET_SEARCH_TERM = 'SET_SEARCH_TERM' } export interface TemplateItem { @@ -82,6 +82,8 @@ export interface TemplateCategory { items: TemplateItem[] } +export type TemplateRepository = TemplateCategory[] + export type MetadataType = Record export type MetadataItem = @@ -102,7 +104,7 @@ export type MetadataItem = } export interface TemplateExplorerProps { - plugin: any + plugin?: any } export interface TopCardProps { From 930c449715b1a89bb920d31a940ee99aacf15f19 Mon Sep 17 00:00:00 2001 From: ci-bot Date: Fri, 26 Sep 2025 16:21:51 +0100 Subject: [PATCH 08/15] finished contract wizard screen --- .../app/src/lib/remix-app/remix-app.tsx | 2 +- .../context/template-explorer-context.tsx | 2 +- .../reducers/contract-wizard-reducer.tsx | 57 + .../src/components/contract-wizard.tsx | 171 ++ .../src/components/notfound.tsx | 11 + .../src/components/template-explorer-body.tsx | 61 +- .../src/components/template-explorer.tsx | 258 +-- .../src/contractCode/erc1155.ts | 1381 +++++++++++++ .../src/contractCode/erc20.ts | 1481 ++++++++++++++ .../src/contractCode/erc721.ts | 1700 +++++++++++++++++ .../lib/remix-ui-template-explorer-modal.tsx | 6 +- .../src/utils/contractWizardUtils.tsx | 540 ++++++ .../types/template-explorer-types.ts | 34 + 13 files changed, 5416 insertions(+), 288 deletions(-) create mode 100644 libs/remix-ui/template-explorer-modal/reducers/contract-wizard-reducer.tsx create mode 100644 libs/remix-ui/template-explorer-modal/src/components/contract-wizard.tsx create mode 100644 libs/remix-ui/template-explorer-modal/src/components/notfound.tsx create mode 100644 libs/remix-ui/template-explorer-modal/src/contractCode/erc1155.ts create mode 100644 libs/remix-ui/template-explorer-modal/src/contractCode/erc20.ts create mode 100644 libs/remix-ui/template-explorer-modal/src/contractCode/erc721.ts create mode 100644 libs/remix-ui/template-explorer-modal/src/utils/contractWizardUtils.tsx diff --git a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx index 42acdd1e046..86c4cc22a41 100644 --- a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx @@ -60,7 +60,7 @@ const RemixApp = (props: IRemixAppUi) => { okFn: () => { }, cancelLabel: 'Default Cancel Label', cancelFn: () => { }, - width: '640px', + width: '720px', height: '720px', showModal: true } diff --git a/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx b/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx index 60e15d39e6b..826d2c19665 100644 --- a/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx +++ b/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx @@ -27,7 +27,7 @@ export const TemplateExplorerProvider = (props: { plugin: TemplateExplorerModalP }, []) const setSearchTerm = (term: string) => { - console.log('setSearchTerm', { term, state }) + console.log('check status', { term, dedupedTemplates, state }) dispatch({ type: TemplateExplorerWizardAction.SET_SEARCH_TERM, payload: term }) } diff --git a/libs/remix-ui/template-explorer-modal/reducers/contract-wizard-reducer.tsx b/libs/remix-ui/template-explorer-modal/reducers/contract-wizard-reducer.tsx new file mode 100644 index 00000000000..568cfe3825a --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/reducers/contract-wizard-reducer.tsx @@ -0,0 +1,57 @@ +import { ContractTypeStrategy } from '../types/template-explorer-types' +import * as erc20 from '../src/contractCode/erc20' +import { ContractWizardAction } from '../types/template-explorer-types' +import { getErc20ContractCode, getErc721ContractCode, getErc1155ContractCode } from '../src/utils/contractWizardUtils' + +const defaultStrategy: ContractTypeStrategy = { + contractType: 'erc20', + contractOptions: { + mintable: false, + burnable: false, + pausable: false + }, + contractAccessControl: '', + contractUpgradability: { + uups: false, + transparent: false + }, + contractCode: erc20.erc20DefaultNoOptions('MyToken'), + contractImport: '', + initializeAsGitRepo: false, + tokenName: 'MyToken' +} + +export function contractWizardReducer(state: ContractTypeStrategy, action: {type: ContractWizardAction, payload: any}) { + switch (action.type) { + case ContractWizardAction.CONTRACT_TYPE_UPDATED: { + return { ...state, contractType: action.payload } + } + case ContractWizardAction.CONTRACT_UPGRADABILITY_UPDATE: { + return { ...state, contractUpgradability: action.payload } + } + case ContractWizardAction.CONTRACT_ACCESS_CONTROL_UPDATE: { + return { ...state, contractAccessControl: action.payload } + } + case ContractWizardAction.CONTRACT_OPTIONS_UPDATE: { + return { ...state, contractOptions: action.payload } + } + case ContractWizardAction.CONTRACT_CODE_UPDATE: { + return { ...state, contractCode: action.payload } + } + case ContractWizardAction.CONTRACT_IMPORT_UPDATE: { + return { ...state, contractImport: action.payload } + } + case ContractWizardAction.INITIALIZE_AS_GIT_REPO_UPDATE: { + return { ...state, initializeAsGitRepo: action.payload } + } + case ContractWizardAction.TOKEN_NAME_UPDATE: { + return { ...state, tokenName: action.payload } + } + case ContractWizardAction.CONTRACT_NAME_UPDATE: { + return { ...state, contractName: action.payload } + } + default: { + return { ...state, contractCode: getErc20ContractCode('erc20', state) } + } + } +} diff --git a/libs/remix-ui/template-explorer-modal/src/components/contract-wizard.tsx b/libs/remix-ui/template-explorer-modal/src/components/contract-wizard.tsx new file mode 100644 index 00000000000..f404d5452a6 --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/components/contract-wizard.tsx @@ -0,0 +1,171 @@ +import React,{ useEffect, useMemo, useReducer, useState } from 'react' +import Editor from '@monaco-editor/react' +import * as erc20 from '../contractCode/erc20' +import * as erc721 from '../contractCode/erc721' +import * as erc1155 from '../contractCode/erc1155' +import { AccessControlType, ContractTypeStrategy, ContractWizardAction } from '../../types/template-explorer-types' +import { contractWizardReducer } from '../../reducers/contract-wizard-reducer' +import { getErc1155ContractCode, getErc20ContractCode, getErc721ContractCode } from '../utils/contractWizardUtils' + +const defaultStrategy: ContractTypeStrategy = { + contractType: 'erc20', + contractOptions: { + mintable: false, + burnable: false, + pausable: false + }, + contractAccessControl: '', + contractUpgradability: { + uups: false, + transparent: false + }, + contractCode: erc20.erc20DefaultNoOptions('MyToken'), + contractImport: '', + initializeAsGitRepo: false +} + +export function ContractWizard () { + const [tokenName, setTokenName] = useState('MyToken') + + const [accessControl, setAccessControl] = useState<'ownable' | 'roles' | 'managed' | ''>('') + const [upgradability, setUpgradability] = useState({ + uups: false, + transparent: false + }) + const [initGit, setInitGit] = useState(false) + const [showEditModal, setShowEditModal] = useState(false) + const [strategy, dispatch] = useReducer(contractWizardReducer, defaultStrategy) + + function toggleContractOption(key: keyof typeof strategy.contractOptions) { + if (key === 'mintable') { + dispatch({ type: ContractWizardAction.CONTRACT_OPTIONS_UPDATE, payload: { ...strategy.contractOptions, [key]: !strategy.contractOptions[key] } }) + switchAccessControl('ownable') + } else if (key === 'pausable') { + dispatch({ type: ContractWizardAction.CONTRACT_OPTIONS_UPDATE, payload: { ...strategy.contractOptions, [key]: !strategy.contractOptions[key] } }) + switchAccessControl('ownable') + } + dispatch({ type: ContractWizardAction.CONTRACT_OPTIONS_UPDATE, payload: { ...strategy.contractOptions, [key]: !strategy.contractOptions[key] } }) + } + + function switchAccessControl(accessControl: AccessControlType) { + console.log('switchAccessControl', accessControl) + dispatch({ type: ContractWizardAction.CONTRACT_ACCESS_CONTROL_UPDATE, payload: accessControl }) + } + function updateTokenName(tokenName: string) { + dispatch({ type: ContractWizardAction.TOKEN_NAME_UPDATE, payload: tokenName }) + } + function updateContractName(contractName: string) { + dispatch({ type: ContractWizardAction.CONTRACT_NAME_UPDATE, payload: contractName }) + } + + useEffect(() => { + // console.log('strategy', strategy) + if (strategy.contractType === 'erc20') { + dispatch({ type: ContractWizardAction.CONTRACT_CODE_UPDATE, payload: getErc20ContractCode(strategy.contractType, strategy) }) + } else if (strategy.contractType === 'erc721') { + dispatch({ type: ContractWizardAction.CONTRACT_CODE_UPDATE, payload: getErc721ContractCode(strategy.contractType, strategy) }) + } else if (strategy.contractType === 'erc1155') { + dispatch({ type: ContractWizardAction.CONTRACT_CODE_UPDATE, payload: getErc1155ContractCode(strategy.contractType, strategy) }) + } + }, [strategy.contractType, strategy.contractOptions, strategy.contractAccessControl, strategy.contractUpgradability, strategy.contractName]) + + return ( +
+
+
+
+ {showEditModal ? setTokenName(e.target.value)} /> : {tokenName}} + setShowEditModal(true)}> +
+
+ + +
+
+ +
+
+
+
Contract settings
+ + updateTokenName(e.target.value)} /> +
+ +
+
Features
+
+ { + toggleContractOption('mintable')} + } /> + +
+
+ toggleContractOption('burnable')} /> + +
+
+ toggleContractOption('pausable')} /> + +
+
+ +
+
Access control
+
+ switchAccessControl('ownable')} /> + +
+
+ switchAccessControl('roles')} /> + +
+
+ switchAccessControl('managed')} /> + +
+
+ +
+
Upgradability
+
+ dispatch({ type: ContractWizardAction.CONTRACT_UPGRADABILITY_UPDATE, payload: { ...strategy.contractUpgradability, uups: !strategy.contractUpgradability.uups } })} /> + +
+
+ dispatch({ type: ContractWizardAction.CONTRACT_UPGRADABILITY_UPDATE, payload: { ...strategy.contractUpgradability, transparent: !strategy.contractUpgradability.transparent } })} /> + +
+
+
+
+ +
+
+ +
+
+
+ setInitGit(e.target.checked)} /> + +
+ +
+
+
+
+ ) +} diff --git a/libs/remix-ui/template-explorer-modal/src/components/notfound.tsx b/libs/remix-ui/template-explorer-modal/src/components/notfound.tsx new file mode 100644 index 00000000000..14f15b8316b --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/components/notfound.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +export function NotFound() { + return ( +
+ Not Found +

No results found

+

Please try again with a different search criteria or choose from our template library

+
+ ) +} diff --git a/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx b/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx index d0c287079e5..3cca1d48341 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/template-explorer-body.tsx @@ -1,50 +1,53 @@ import React, { useContext } from 'react' -import { TopCard } from './topCard' -import { TopCardProps } from '../../types/template-explorer-types' import { TemplateExplorer } from './template-explorer' import { TopCards } from './topCards' import { TemplateExplorerContext } from '../../context/template-explorer-context' +import { NotFound } from './notfound' export interface TemplateExplorerBodyProps { plugin: any } export function TemplateExplorerBody({ plugin }: TemplateExplorerBodyProps) { - const { selectedTag, allTags, handleTagClick, clearFilter } = useContext(TemplateExplorerContext) + const { selectedTag, allTags, handleTagClick, clearFilter, dedupedTemplates } = useContext(TemplateExplorerContext) const filterTheseTags = tag => tag !== 'Circom' && tag !== 'All' && tag !== 'Noir' && tag !== 'AI' return (
-
- - {/* Tag Filter Row */} -
-
+ { + (dedupedTemplates.length === 0) ? : ( +
+ <> + +
+
- {allTags?.filter(filterTheseTags)?.reverse()?.map((tag: any) => ( - handleTagClick(tag as any)} - > - {tag as any} - - ))} - {selectedTag && ( - - + {allTags?.filter(filterTheseTags)?.reverse()?.map((tag: any) => ( + handleTagClick(tag as any)} + > + {tag as any} + + ))} + {selectedTag && ( + + Clear filter - - - )} + + + )} +
+
+ +
-
- -
+ )}
) } diff --git a/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx b/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx index 1db82736d94..5697b1e8b8b 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/template-explorer.tsx @@ -5,264 +5,11 @@ import { TemplateExplorerContext } from '../../context/template-explorer-context export function TemplateExplorer() { - const { metadata, recentTemplates, dedupedTemplates, addRecentTemplate, plugin } = useContext(TemplateExplorerContext) - - // console.log('metadata', metadata) - // console.log('templatesRepository', templatesRepository) - - // Get all unique tags from all templates - // const allTags = useMemo((): string[] => { - // const tags: string[] = [] - - // if (templateRepository && Array.isArray(templateRepository)) { - // templateRepository.forEach((template: any) => { - // if (template && template.items && Array.isArray(template.items)) { - // template.items.forEach((item: any) => { - // if (item && item.tagList && Array.isArray(item.tagList)) { - // item.tagList.forEach((tag: string) => { - // if (typeof tag === 'string' && !tags.includes(tag)) { - // tags.push(tag) - // } - // }) - // } - // }) - // } - // }) - // } - - // return tags.sort() - // }, []) - - // // Recent templates (before filteredTemplates so it can be referenced later) - // const recentTemplates = useMemo((): TemplateItem[] => { - // try { - // const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null - // const list: string[] = raw ? JSON.parse(raw) : [] - // const items: TemplateItem[] = [] - // if (Array.isArray(templateRepository)) { - // list.forEach((val) => { - // for (const group of templateRepository as any[]) { - // if (group && Array.isArray(group.items)) { - // const found = group.items.find((it: any) => it && it.value === val) - // if (found) { - // items.push(found) - // break - // } - // } - // } - // }) - // } - // //tag filter - // const filtered = selectedTag - // ? items.filter((it: any) => it && Array.isArray(it.tagList) && it.tagList.includes(selectedTag)) - // : items - // return filtered - // } catch (e) { - // return [] - // } - // }, [selectedTag, recentBump]) - - // // Filter templates based on selected tag - // const filteredTemplates = useMemo((): TemplateCategory[] => { - // if (!selectedTag || !templateRepository || !Array.isArray(templateRepository)) { - // return templateRepository as TemplateCategory[] || [] - // } - - // return (templateRepository as TemplateCategory[]).map((template: any) => ({ - // ...template, - // items: template.items.filter((item: any) => - // item && item.tagList && Array.isArray(item.tagList) && item.tagList.includes(selectedTag) - // ) - // })).filter((template: any) => template && template.items && template.items.length > 0) - // }, [selectedTag]) - - // // Dedupe templates across the whole page and avoid showing ones already in recents - // const dedupedTemplates = useMemo((): TemplateCategory[] => { - // const recentSet = new Set((recentTemplates || []).map((t: any) => t && t.value)) - // const seen = new Set() - // const makeUniqueItems = (items: any[]) => { - // const unique: any[] = [] - // for (const it of items || []) { - // const val = it && it.value - // if (!val) continue - // if (recentSet.has(val)) continue - // if (seen.has(val)) continue - // seen.add(val) - // unique.push(it) - // } - // return unique - // } - // return (filteredTemplates || []).map((group: any) => ({ - // ...group, - // items: makeUniqueItems(group && group.items ? group.items : []) - // })).filter((g: any) => g && g.items && g.items.length > 0) - // }, [filteredTemplates, recentTemplates]) - - // const handleTagClick = (tag: string) => { - // setSelectedTag(selectedTag === tag ? null : tag) - // } - - // const clearFilter = () => { - // setSelectedTag(null) - // } - - // const RECENT_KEY = 'remix.recentTemplates' - - // const addRecentTemplate = (templateValue: string) => { - // try { - // const raw = typeof window !== 'undefined' ? window.localStorage.getItem(RECENT_KEY) : null - // const list: string[] = raw ? JSON.parse(raw) : [] - // const filtered = list.filter((v) => v !== templateValue) - // filtered.unshift(templateValue) - // const trimmed = filtered.slice(0, 4) - // if (typeof window !== 'undefined') window.localStorage.setItem(RECENT_KEY, JSON.stringify(trimmed)) - // setRecentBump((v) => v + 1) - // } catch (e) { - - // } - // } + const { metadata, dedupedTemplates, addRecentTemplate, plugin } = useContext(TemplateExplorerContext) return (
- {/* Recently Used Section */} - {/* {recentTemplates && recentTemplates?.length > 0 && ( -
-

- Recently used -

-
- {recentTemplates?.map((item: TemplateItem, itemIndex) => { - item.templateType = metadata[item.value] - if (item.templateType && item.templateType.disabled === true) return null - if (item.templateType && item.templateType.desktopCompatible === false && isElectron()) return null - return ( -
{ - addRecentTemplate(item) - }} - onMouseEnter={(e) => { - e.currentTarget.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)' - e.currentTarget.style.transform = 'translateY(-2px)' - }} - onMouseLeave={(e) => { - e.currentTarget.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)' - e.currentTarget.style.transform = 'translateY(0)' - }} - > -
-
- {item.displayName || item.value} -
- {item.tagList && item.tagList.length > 0 && ( -
- {item.tagList.map((tag, tagIndex) => ( - - {tag} - - ))} -
- )} -
-
- {item.description && ( -

- {item.description} -

- )} - {item.opts && Object.keys(item.opts).length > 0 && ( -
- {item.opts.upgradeable && ( - - UUPS - - )} - {item.opts.mintable && ( - - Mint - - )} - {item.opts.burnable && ( - - Burn - - )} - {item.opts.pausable && ( - - Pause - - )} -
- )} -
-
- ) - })} -
-
- )} */} - {dedupedTemplates?.map((template: TemplateCategory, templateIndex) => (

{template.description && ( -

+

{template.description}

)} @@ -407,7 +154,6 @@ export function TemplateExplorer() { })}

- {/* Special handling for Cookbook section */} {template.name === 'Cookbook' && (
` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC1155Upgradeable, OwnableUpgradeable, ERC1155PausableUpgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC1155_init(""); + __Ownable_init(initialOwner); + __ERC1155Pausable_init(); + __ERC1155Burnable_init(); + __UUPSUpgradeable_init(); + } + + function setURI(string memory newuri) public onlyOwner { + _setURI(newuri); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyOwner + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyOwner + { + _mintBatch(to, ids, amounts, data); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } +} +` +export const erc1155RolesFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC1155Upgradeable, AccessControlUpgradeable, ERC1155PausableUpgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable { + bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address minter, address upgrader) + public + initializer + { + __ERC1155_init(""); + __AccessControl_init(); + __ERC1155Pausable_init(); + __ERC1155Burnable_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function setURI(string memory newuri) public onlyRole(URI_SETTER_ROLE) { + _setURI(newuri); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyRole(MINTER_ROLE) + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyRole(MINTER_ROLE) + { + _mintBatch(to, ids, amounts, data); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC1155Upgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc1155ManagedFullOptions = (contractName: string) =>` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC1155Upgradeable, AccessManagedUpgradeable, ERC1155PausableUpgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC1155_init(""); + __AccessManaged_init(initialAuthority); + __ERC1155Pausable_init(); + __ERC1155Burnable_init(); + __UUPSUpgradeable_init(); + } + + function setURI(string memory newuri) public restricted { + _setURI(newuri); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + restricted + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + restricted + { + _mintBatch(to, ids, amounts, data); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155ManagedTransparentFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract ${contractName} is Initializable, ERC1155Upgradeable, AccessManagedUpgradeable, ERC1155PausableUpgradeable, ERC1155BurnableUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC1155_init(""); + __AccessManaged_init(initialAuthority); + __ERC1155Pausable_init(); + __ERC1155Burnable_init(); + } + + function setURI(string memory newuri) public restricted { + _setURI(newuri); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + restricted + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + restricted + { + _mintBatch(to, ids, amounts, data); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155RolesTransparentFullOptions = ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract MyToken is Initializable, ERC1155Upgradeable, AccessControlUpgradeable, ERC1155PausableUpgradeable, ERC1155BurnableUpgradeable { + bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address minter) + public + initializer + { + __ERC1155_init(""); + __AccessControl_init(); + __ERC1155Pausable_init(); + __ERC1155Burnable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + } + + function setURI(string memory newuri) public onlyRole(URI_SETTER_ROLE) { + _setURI(newuri); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyRole(MINTER_ROLE) + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyRole(MINTER_ROLE) + { + _mintBatch(to, ids, amounts, data); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC1155Upgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc1155OwnableTransparentFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC1155Upgradeable, OwnableUpgradeable, ERC1155PausableUpgradeable, ERC1155BurnableUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC1155_init(""); + __Ownable_init(initialOwner); + __ERC1155Pausable_init(); + __ERC1155Burnable_init(); + } + + function setURI(string memory newuri) public onlyOwner { + _setURI(newuri); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyOwner + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyOwner + { + _mintBatch(to, ids, amounts, data); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155PausableBurnableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {ERC1155Burnable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; +import {ERC1155Pausable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC1155, Ownable, ERC1155Pausable, ERC1155Burnable { + constructor(address initialOwner) ERC1155("") Ownable(initialOwner) {} + + function setURI(string memory newuri) public onlyOwner { + _setURI(newuri); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyOwner + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyOwner + { + _mintBatch(to, ids, amounts, data); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155, ERC1155Pausable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155DefaultOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC1155, Ownable { + constructor(address initialOwner) ERC1155("") Ownable(initialOwner) {} + + function setURI(string memory newuri) public onlyOwner { + _setURI(newuri); + } +} +` + +export const erc1155PausableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {ERC1155Pausable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC1155, Ownable, ERC1155Pausable { + constructor(address initialOwner) ERC1155("") Ownable(initialOwner) {} + + function setURI(string memory newuri) public onlyOwner { + _setURI(newuri); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155, ERC1155Pausable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155BurnableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {ERC1155Burnable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC1155, Ownable, ERC1155Burnable { + constructor(address initialOwner) ERC1155("") Ownable(initialOwner) {} + + function setURI(string memory newuri) public onlyOwner { + _setURI(newuri); + } +} +` + +export const erc1155MintableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC1155, Ownable { + constructor(address initialOwner) ERC1155("") Ownable(initialOwner) {} + + function setURI(string memory newuri) public onlyOwner { + _setURI(newuri); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyOwner + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyOwner + { + _mintBatch(to, ids, amounts, data); + } +} +` + +export const erc1155MintableBurnablePausableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {ERC1155Burnable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; +import {ERC1155Pausable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol"; +import {ERC1155Supply} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC1155, Ownable, ERC1155Pausable, ERC1155Burnable, ERC1155Supply { + constructor(address initialOwner) ERC1155("") Ownable(initialOwner) {} + + function setURI(string memory newuri) public onlyOwner { + _setURI(newuri); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyOwner + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyOwner + { + _mintBatch(to, ids, amounts, data); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155, ERC1155Pausable, ERC1155Supply) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155MintablePausableBurnableRolesOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {ERC1155Burnable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; +import {ERC1155Pausable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol"; + +contract ${contractName} is ERC1155, AccessControl, ERC1155Pausable, ERC1155Burnable { + bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + + constructor(address defaultAdmin, address pauser, address minter) ERC1155("") { + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + } + + function setURI(string memory newuri) public onlyRole(URI_SETTER_ROLE) { + _setURI(newuri); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyRole(MINTER_ROLE) + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyRole(MINTER_ROLE) + { + _mintBatch(to, ids, amounts, data); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155, ERC1155Pausable) + { + super._update(from, to, ids, values); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC1155, AccessControl) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc1155UUPSOwnableMintableBurnablePausableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC1155Upgradeable, ERC1155PausableUpgradeable, OwnableUpgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC1155_init(""); + __ERC1155Pausable_init(); + __Ownable_init(initialOwner); + __ERC1155Burnable_init(); + __UUPSUpgradeable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyOwner + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyOwner + { + _mintBatch(to, ids, amounts, data); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155MintablePausableBurnableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {ERC1155Burnable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; +import {ERC1155Pausable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol"; + +contract ${contractName} is ERC1155, AccessManaged, ERC1155Pausable, ERC1155Burnable { + constructor(address initialAuthority) + ERC1155("") + AccessManaged(initialAuthority) + {} + + function setURI(string memory newuri) public restricted { + _setURI(newuri); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + restricted + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + restricted + { + _mintBatch(to, ids, amounts, data); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155, ERC1155Pausable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155MintableBurnableRolesOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC1155Upgradeable, ERC1155PausableUpgradeable, OwnableUpgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC1155_init(""); + __ERC1155Pausable_init(); + __Ownable_init(initialOwner); + __ERC1155Burnable_init(); + __UUPSUpgradeable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyOwner + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyOwner + { + _mintBatch(to, ids, amounts, data); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155UUPSOwnableFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC1155Upgradeable, ERC1155PausableUpgradeable, OwnableUpgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC1155_init(""); + __ERC1155Pausable_init(); + __Ownable_init(initialOwner); + __ERC1155Burnable_init(); + __UUPSUpgradeable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyOwner + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyOwner + { + _mintBatch(to, ids, amounts, data); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155UUPSRolesFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC1155Upgradeable, ERC1155PausableUpgradeable, AccessControlUpgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address minter, address upgrader) + public + initializer + { + __ERC1155_init(""); + __ERC1155Pausable_init(); + __AccessControl_init(); + __ERC1155Burnable_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyRole(MINTER_ROLE) + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyRole(MINTER_ROLE) + { + _mintBatch(to, ids, amounts, data); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC1155Upgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc1155UUPSManagedFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC1155Upgradeable, ERC1155PausableUpgradeable, AccessManagedUpgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC1155_init(""); + __ERC1155Pausable_init(); + __AccessManaged_init(initialAuthority); + __ERC1155Burnable_init(); + __UUPSUpgradeable_init(); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + restricted + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + restricted + { + _mintBatch(to, ids, amounts, data); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155UUPSManagedTransparentFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract MyToken is Initializable, ERC1155Upgradeable, ERC1155PausableUpgradeable, AccessManagedUpgradeable, ERC1155BurnableUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC1155_init(""); + __ERC1155Pausable_init(); + __AccessManaged_init(initialAuthority); + __ERC1155Burnable_init(); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + restricted + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + restricted + { + _mintBatch(to, ids, amounts, data); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155TransparentOwnableFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; + +contract MyToken is Initializable, ERC1155Upgradeable, ERC1155PausableUpgradeable, OwnableUpgradeable, ERC1155BurnableUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC1155_init(""); + __ERC1155Pausable_init(); + __Ownable_init(initialOwner); + __ERC1155Burnable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyOwner + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyOwner + { + _mintBatch(to, ids, amounts, data); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } +} +` + +export const erc1155BurnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {ERC1155Burnable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; + +contract MyToken is ERC1155, ERC1155Burnable { + constructor() ERC1155("") {} +} +` + +export const erc1155TransparentRolesFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; +import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; +import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract MyToken is Initializable, ERC1155Upgradeable, ERC1155PausableUpgradeable, AccessControlUpgradeable, ERC1155BurnableUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address minter) + public + initializer + { + __ERC1155_init(""); + __ERC1155Pausable_init(); + __AccessControl_init(); + __ERC1155Burnable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function mint(address account, uint256 id, uint256 amount, bytes memory data) + public + onlyRole(MINTER_ROLE) + { + _mint(account, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) + public + onlyRole(MINTER_ROLE) + { + _mintBatch(to, ids, amounts, data); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155Upgradeable, ERC1155PausableUpgradeable) + { + super._update(from, to, ids, values); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC1155Upgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc1155PausableRolesOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {ERC1155Pausable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol"; + +contract MyToken is ERC1155, ERC1155Pausable, AccessControl { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + constructor(address defaultAdmin, address pauser) ERC1155("") { + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155, ERC1155Pausable) + { + super._update(from, to, ids, values); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC1155, AccessControl) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc1155PausableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {ERC1155Pausable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol"; + +contract MyToken is ERC1155, ERC1155Pausable, AccessManaged { + constructor(address initialAuthority) + ERC1155("") + AccessManaged(initialAuthority) + {} + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) + internal + override(ERC1155, ERC1155Pausable) + { + super._update(from, to, ids, values); + } +} +` + diff --git a/libs/remix-ui/template-explorer-modal/src/contractCode/erc20.ts b/libs/remix-ui/template-explorer-modal/src/contractCode/erc20.ts new file mode 100644 index 00000000000..d99a5ad119c --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/contractCode/erc20.ts @@ -0,0 +1,1481 @@ +export const erc20DefaultNoOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract ${contractName} is ERC20 { + constructor() ERC20("MyToken", "MTK") {} +} +` + +export const erc20MintableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC20, Ownable { + constructor(address initialOwner) + ERC20("MyToken", "MTK") + Ownable(initialOwner) + {} + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } +} +` + +export const erc20MintablePausableBurnableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20PausableUpgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __ERC20Pausable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} + +` + +export const erc20MintablePausableBurnableRolesOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20PausableUpgradeable, AccessControlUpgradeable, UUPSUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address minter, address upgrader) + public + initializer + { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __ERC20Pausable_init(); + __AccessControl_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} + +` + +export const erc20MintablePausableBurnableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20PausableUpgradeable, AccessManagedUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __ERC20Pausable_init(); + __AccessManaged_init(initialAuthority); + __UUPSUpgradeable_init(); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} + +` + +export const erc20BurnableMintableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC20, ERC20Burnable, Ownable { + constructor(address initialOwner) + ERC20("MyToken", "MTK") + Ownable(initialOwner) + {} + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } +} +` + +export const erc20PausableBurnableMintableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import {ERC20Pausable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC20, ERC20Burnable, ERC20Pausable, Ownable { + constructor(address initialOwner) + ERC20("MyToken", "MTK") + Ownable(initialOwner) + {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20, ERC20Pausable) + { + super._update(from, to, value); + } +} +` + +export const erc20MintableRolesOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract ${contractName} is ERC20, AccessControl { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + + constructor(address defaultAdmin, address minter) ERC20("MyToken", "MTK") { + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(MINTER_ROLE, minter); + } + + function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { + _mint(to, amount); + } +} +` + +export const erc20MintableBurnableRolesOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; + +contract ${contractName} is ERC20, ERC20Burnable, AccessControl { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + + constructor(address defaultAdmin, address minter) ERC20("MyToken", "MTK") { + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(MINTER_ROLE, minter); + } + + function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { + _mint(to, amount); + } +} +` + +export const erc20MintableBurnablePausableRolesOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import {ERC20Pausable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; + +contract ${contractName} is ERC20, ERC20Burnable, ERC20Pausable, AccessControl { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + + constructor(address defaultAdmin, address pauser, address minter) + ERC20("MyToken", "MTK") + { + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { + _mint(to, amount); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20, ERC20Pausable) + { + super._update(from, to, value); + } +} +` + +export const erc20MintableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract ${contractName} is ERC20, AccessManaged { + constructor(address initialAuthority) + ERC20("MyToken", "MTK") + AccessManaged(initialAuthority) + {} + + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } +} +` + +export const erc20MintableBurnableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; + +contract ${contractName} is ERC20, ERC20Burnable, AccessManaged { + constructor(address initialAuthority) + ERC20("MyToken", "MTK") + AccessManaged(initialAuthority) + {} + + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } +} +` + +export const erc20MintableBurnablePausableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import {ERC20Pausable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; + +contract ${contractName} is ERC20, ERC20Burnable, ERC20Pausable, AccessManaged { + constructor(address initialAuthority) + ERC20("MyToken", "MTK") + AccessManaged(initialAuthority) + {} + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20, ERC20Pausable) + { + super._update(from, to, value); + } +} +` + +export const erc20TransparentNoOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize() public initializer { + __ERC20_init("MyToken", "MTK"); + } +} +` + +export const erc20TransparentMintableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, AccessManagedUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC20_init("MyToken", "MTK"); + __AccessManaged_init(initialAuthority); + } + + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } +} +` + +export const erc20TransparentMintableBurnableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, AccessManagedUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __AccessManaged_init(initialAuthority); + } + + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } +} +` + +export const erc20TransparentMintableBurnablePausableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20PausableUpgradeable, AccessManagedUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __ERC20Pausable_init(); + __AccessManaged_init(initialAuthority); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} +` + +export const erc20UUPSManagedFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20PausableUpgradeable, AccessManagedUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __ERC20Pausable_init(); + __AccessManaged_init(initialAuthority); + __UUPSUpgradeable_init(); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} +` + +export const erc20UUPSManagedMintableBurnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, AccessManagedUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __AccessManaged_init(initialAuthority); + __UUPSUpgradeable_init(); + } + + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} +} +` + +export const erc20UUPSManagedMintableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, AccessManagedUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC20_init("MyToken", "MTK"); + __AccessManaged_init(initialAuthority); + __UUPSUpgradeable_init(); + } + + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} +} +` + +export const erc20UUPSManagedNoOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, AccessManagedUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC20_init("MyToken", "MTK"); + __AccessManaged_init(initialAuthority); + __UUPSUpgradeable_init(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} +} +` + +export const erc20UUPSRolesNoOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, AccessControlUpgradeable, UUPSUpgradeable { + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address upgrader) public initializer { + __ERC20_init("MyToken", "MTK"); + __AccessControl_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} +} +` + +export const erc20UUPSRolesMintableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, AccessControlUpgradeable, UUPSUpgradeable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address minter, address upgrader) + public + initializer + { + __ERC20_init("MyToken", "MTK"); + __AccessControl_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(MINTER_ROLE, minter); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} +} +` + +export const erc20UUPSRolesMintableBurnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, AccessControlUpgradeable, UUPSUpgradeable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address minter, address upgrader) + public + initializer + { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __AccessControl_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(MINTER_ROLE, minter); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} +} +` + +export const erc20UUPSRolesFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20PausableUpgradeable, AccessControlUpgradeable, UUPSUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address minter, address upgrader) + public + initializer + { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __ERC20Pausable_init(); + __AccessControl_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} +` + +export const erc20UUPSOwnableNoOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("MyToken", "MTK"); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} +} +` + +export const erc20UUPSOwnableMintableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("MyToken", "MTK"); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} +} +` + +export const erc20UUPSOwnableMintableBurnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} +} +` + +export const erc20UUPSOwnableMintableBurnablePausableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20PausableUpgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __ERC20Pausable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} +` + +export const erc20MintablePausableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} +} + +` + +export const erc20UUPSBurnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} +} + +` + +export const erc20UUPSPausableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20PausableUpgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Pausable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} + +` + +export const erc20BurnableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract MyToken is ERC20, ERC20Burnable, Ownable { + constructor(address initialOwner) + ERC20("MyToken", "MTK") + Ownable(initialOwner) + {} +} + +` + +export const erc20UUPSOwnableBurnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, OwnableUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __Ownable_init(initialOwner); + } +} + +` + +export const erc20TransparentBurnableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, AccessManagedUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Burnable_init(); + __AccessManaged_init(initialAuthority); + } +} + +` + +export const erc20OwnableBurnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract MyToken is ERC20, ERC20Burnable, Ownable { + constructor(address initialOwner) + ERC20("MyToken", "MTK") + Ownable(initialOwner) + {} + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } +} + +` + +export const erc20UUPSOwnablePausableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20PausableUpgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Pausable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} + +` + +export const erc20TransparentPausableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20PausableUpgradeable, AccessControlUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Pausable_init(); + __AccessControl_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} + +` + +export const erc20UUPSRolesPausableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20PausableUpgradeable, AccessControlUpgradeable, UUPSUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address upgrader) + public + initializer + { + __ERC20_init("MyToken", "MTK"); + __ERC20Pausable_init(); + __AccessControl_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} + +` + +export const UUPSManagedPausableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC20Upgradeable, ERC20PausableUpgradeable, AccessManagedUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC20_init("MyToken", "MTK"); + __ERC20Pausable_init(); + __AccessManaged_init(initialAuthority); + __UUPSUpgradeable_init(); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._update(from, to, value); + } +} +` + diff --git a/libs/remix-ui/template-explorer-modal/src/contractCode/erc721.ts b/libs/remix-ui/template-explorer-modal/src/contractCode/erc721.ts new file mode 100644 index 00000000000..468823c7979 --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/contractCode/erc721.ts @@ -0,0 +1,1700 @@ +export const erc721DefaultNoOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +contract ${contractName} is ERC721 { + constructor() ERC721("MyToken", "MTK") {} +} +` + +export const erc721MintableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC721, Ownable { + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} + + function safeMint(address to, uint256 tokenId) public onlyOwner { + _safeMint(to, tokenId); + } +} +` + +export const erc721MintableOwnableAutoIncrementOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC721, Ownable { + uint256 private _nextTokenId; + + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} + + function safeMint(address to) public onlyOwner returns (uint256) { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + return tokenId; + } +}` + +export const erc721BurnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; + +contract ${contractName} is ERC721, ERC721Burnable { + constructor() ERC721("MyToken", "MTK") {} +} +` + +export const erc721BurnableMintableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC721, ERC721Burnable, Ownable { + uint256 private _nextTokenId; + + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} + + function safeMint(address to) public onlyOwner returns (uint256) { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + return tokenId; + } +} +` + +export const erc721PauableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Pausable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC721, ERC721Pausable, Ownable { + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721, ERC721Pausable) + returns (address) + { + return super._update(to, tokenId, auth); + } +} +` + +export const erc721PausableBurnableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import {ERC721Pausable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC721, ERC721Pausable, Ownable, ERC721Burnable { + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721, ERC721Pausable) + returns (address) + { + return super._update(to, tokenId, auth); + } +} +` + +export const erc721PausableBurnableMintableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import {ERC721Pausable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC721, ERC721Pausable, Ownable, ERC721Burnable { + uint256 private _nextTokenId; + + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function safeMint(address to) public onlyOwner returns (uint256) { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + return tokenId; + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721, ERC721Pausable) + returns (address) + { + return super._update(to, tokenId, auth); + } +} +` + +export const erc721PausableBurnableMintableEnumerableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import {ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import {ERC721Pausable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC721, ERC721Enumerable, ERC721Pausable, Ownable, ERC721Burnable { + uint256 private _nextTokenId; + + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function safeMint(address to) public onlyOwner returns (uint256) { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + return tokenId; + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721, ERC721Enumerable, ERC721Pausable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721, ERC721Enumerable) + { + super._increaseBalance(account, value); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721, ERC721Enumerable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721FullOptionsUriStorage = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import {ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import {ERC721Pausable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; +import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ${contractName} is ERC721, ERC721Enumerable, ERC721URIStorage, ERC721Pausable, Ownable, ERC721Burnable { + uint256 private _nextTokenId; + + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function safeMint(address to, string memory uri) + public + onlyOwner + returns (uint256) + { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + return tokenId; + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721, ERC721Enumerable, ERC721Pausable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721, ERC721Enumerable) + { + super._increaseBalance(account, value); + } + + function tokenURI(uint256 tokenId) + public + view + override(ERC721, ERC721URIStorage) + returns (string memory) + { + return super.tokenURI(tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721, ERC721Enumerable, ERC721URIStorage) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721FullOptionsRoles = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import {ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import {ERC721Pausable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; +import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; + +contract ${contractName} is ERC721, ERC721Enumerable, ERC721URIStorage, ERC721Pausable, AccessControl, ERC721Burnable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + uint256 private _nextTokenId; + + constructor(address defaultAdmin, address pauser, address minter) + ERC721("MyToken", "MTK") + { + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function safeMint(address to, string memory uri) + public + onlyRole(MINTER_ROLE) + returns (uint256) + { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + return tokenId; + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721, ERC721Enumerable, ERC721Pausable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721, ERC721Enumerable) + { + super._increaseBalance(account, value); + } + + function tokenURI(uint256 tokenId) + public + view + override(ERC721, ERC721URIStorage) + returns (string memory) + { + return super.tokenURI(tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721, ERC721Enumerable, ERC721URIStorage, AccessControl) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721ManagedFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import {ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import {ERC721Pausable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; +import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; + +contract ${contractName} is ERC721, ERC721Enumerable, ERC721URIStorage, ERC721Pausable, AccessManaged, ERC721Burnable { + uint256 private _nextTokenId; + + constructor(address initialAuthority) + ERC721("MyToken", "MTK") + AccessManaged(initialAuthority) + {} + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function safeMint(address to, string memory uri) + public + restricted + returns (uint256) + { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + return tokenId; + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721, ERC721Enumerable, ERC721Pausable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721, ERC721Enumerable) + { + super._increaseBalance(account, value); + } + + function tokenURI(uint256 tokenId) + public + view + override(ERC721, ERC721URIStorage) + returns (string memory) + { + return super.tokenURI(tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721, ERC721Enumerable, ERC721URIStorage) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721FullOptionsManagedTransparent = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract ${contractName} is Initializable, ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, ERC721PausableUpgradeable, AccessManagedUpgradeable, ERC721BurnableUpgradeable { + uint256 private _nextTokenId; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC721_init("MyToken", "MTK"); + __ERC721Enumerable_init(); + __ERC721URIStorage_init(); + __ERC721Pausable_init(); + __AccessManaged_init(initialAuthority); + __ERC721Burnable_init(); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function safeMint(address to, string memory uri) + public + restricted + returns (uint256) + { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + return tokenId; + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable) + { + super._increaseBalance(account, value); + } + + function tokenURI(uint256 tokenId) + public + view + override(ERC721Upgradeable, ERC721URIStorageUpgradeable) + returns (string memory) + { + return super.tokenURI(tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721FullOptionsRolesTransparent = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract ${contractName} is Initializable, ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, ERC721PausableUpgradeable, AccessControlUpgradeable, ERC721BurnableUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + uint256 private _nextTokenId; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address minter) + public + initializer + { + __ERC721_init("MyToken", "MTK"); + __ERC721Enumerable_init(); + __ERC721URIStorage_init(); + __ERC721Pausable_init(); + __AccessControl_init(); + __ERC721Burnable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function safeMint(address to, string memory uri) + public + onlyRole(MINTER_ROLE) + returns (uint256) + { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + return tokenId; + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable) + { + super._increaseBalance(account, value); + } + + function tokenURI(uint256 tokenId) + public + view + override(ERC721Upgradeable, ERC721URIStorageUpgradeable) + returns (string memory) + { + return super.tokenURI(tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721ManagedFullOptionsTransparent = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract ${contractName} is Initializable, ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, ERC721PausableUpgradeable, AccessManagedUpgradeable, ERC721BurnableUpgradeable { + uint256 private _nextTokenId; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC721_init("MyToken", "MTK"); + __ERC721Enumerable_init(); + __ERC721URIStorage_init(); + __ERC721Pausable_init(); + __AccessManaged_init(initialAuthority); + __ERC721Burnable_init(); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function safeMint(address to, string memory uri) + public + restricted + returns (uint256) + { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + return tokenId; + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable) + { + super._increaseBalance(account, value); + } + + function tokenURI(uint256 tokenId) + public + view + override(ERC721Upgradeable, ERC721URIStorageUpgradeable) + returns (string memory) + { + return super.tokenURI(tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721UUPSManagedFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, ERC721PausableUpgradeable, AccessManagedUpgradeable, ERC721BurnableUpgradeable, UUPSUpgradeable { + uint256 private _nextTokenId; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC721_init("MyToken", "MTK"); + __ERC721Enumerable_init(); + __ERC721URIStorage_init(); + __ERC721Pausable_init(); + __AccessManaged_init(initialAuthority); + __ERC721Burnable_init(); + __UUPSUpgradeable_init(); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function safeMint(address to, string memory uri) + public + restricted + returns (uint256) + { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + return tokenId; + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable) + { + super._increaseBalance(account, value); + } + + function tokenURI(uint256 tokenId) + public + view + override(ERC721Upgradeable, ERC721URIStorageUpgradeable) + returns (string memory) + { + return super.tokenURI(tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721UUPSRolesFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, ERC721PausableUpgradeable, AccessControlUpgradeable, ERC721BurnableUpgradeable, UUPSUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + uint256 private _nextTokenId; + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address minter, address upgrader) + public + initializer + { + __ERC721_init("MyToken", "MTK"); + __ERC721Enumerable_init(); + __ERC721URIStorage_init(); + __ERC721Pausable_init(); + __AccessControl_init(); + __ERC721Burnable_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function safeMint(address to, string memory uri) + public + onlyRole(MINTER_ROLE) + returns (uint256) + { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + return tokenId; + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable) + { + super._increaseBalance(account, value); + } + + function tokenURI(uint256 tokenId) + public + view + override(ERC721Upgradeable, ERC721URIStorageUpgradeable) + returns (string memory) + { + return super.tokenURI(tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721UUPSOwnableFullOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract ${contractName} is Initializable, ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, ERC721PausableUpgradeable, OwnableUpgradeable, ERC721BurnableUpgradeable, UUPSUpgradeable { + uint256 private _nextTokenId; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC721_init("MyToken", "MTK"); + __ERC721Enumerable_init(); + __ERC721URIStorage_init(); + __ERC721Pausable_init(); + __Ownable_init(initialOwner); + __ERC721Burnable_init(); + __UUPSUpgradeable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function safeMint(address to, string memory uri) + public + onlyOwner + returns (uint256) + { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + return tokenId; + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable) + { + super._increaseBalance(account, value); + } + + function tokenURI(uint256 tokenId) + public + view + override(ERC721Upgradeable, ERC721URIStorageUpgradeable) + returns (string memory) + { + return super.tokenURI(tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721PausableMintableRoleOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC721Upgradeable, ERC721PausableUpgradeable, AccessControlUpgradeable, ERC721BurnableUpgradeable, UUPSUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address minter, address upgrader) + public + initializer + { + __ERC721_init("MyToken", "MTK"); + __ERC721Pausable_init(); + __AccessControl_init(); + __ERC721Burnable_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function safeMint(address to, uint256 tokenId) public onlyRole(MINTER_ROLE) { + _safeMint(to, tokenId); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721PausableBurnableRoleOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC721Upgradeable, ERC721PausableUpgradeable, AccessControlUpgradeable, ERC721BurnableUpgradeable, UUPSUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address upgrader) + public + initializer + { + __ERC721_init("MyToken", "MTK"); + __ERC721Pausable_init(); + __AccessControl_init(); + __ERC721Burnable_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721ManagedMintableBurnablePausableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import {ERC721Pausable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; + +contract MyToken is ERC721, ERC721Pausable, AccessManaged, ERC721Burnable { + constructor(address initialAuthority) + ERC721("MyToken", "MTK") + AccessManaged(initialAuthority) + {} + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function safeMint(address to, uint256 tokenId) public restricted { + _safeMint(to, tokenId); + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721, ERC721Pausable) + returns (address) + { + return super._update(to, tokenId, auth); + } +} + +` + +export const erc721MintableRolesOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC721Upgradeable, AccessControlUpgradeable, UUPSUpgradeable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address minter, address upgrader) + public + initializer + { + __ERC721_init("MyToken", "MTK"); + __AccessControl_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(MINTER_ROLE, minter); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function safeMint(address to, uint256 tokenId) public onlyRole(MINTER_ROLE) { + _safeMint(to, tokenId); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} + +` + +export const erc721MintableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC721Upgradeable, AccessManagedUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC721_init("MyToken", "MTK"); + __AccessManaged_init(initialAuthority); + __UUPSUpgradeable_init(); + } + + function safeMint(address to, uint256 tokenId) public restricted { + _safeMint(to, tokenId); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} +} + +` + +export const erc721UUPSMintablePausableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC721Upgradeable, ERC721PausableUpgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC721_init("MyToken", "MTK"); + __ERC721Pausable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function safeMint(address to, uint256 tokenId) public onlyOwner { + _safeMint(to, tokenId); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } +} +` + +export const erc721UUPSMintablePausableRolesOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC721Upgradeable, ERC721PausableUpgradeable, AccessControlUpgradeable, UUPSUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address minter, address upgrader) + public + initializer + { + __ERC721_init("MyToken", "MTK"); + __ERC721Pausable_init(); + __AccessControl_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(MINTER_ROLE, minter); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function safeMint(address to, uint256 tokenId) public onlyRole(MINTER_ROLE) { + _safeMint(to, tokenId); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721UUPSMintablePausableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC721Upgradeable, ERC721PausableUpgradeable, AccessManagedUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC721_init("MyToken", "MTK"); + __ERC721Pausable_init(); + __AccessManaged_init(initialAuthority); + __UUPSUpgradeable_init(); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function safeMint(address to, uint256 tokenId) public restricted { + _safeMint(to, tokenId); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } +} +` + +export const erc721UUPSBurnablePausableOwnableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC721Upgradeable, ERC721PausableUpgradeable, OwnableUpgradeable, ERC721BurnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC721_init("MyToken", "MTK"); + __ERC721Pausable_init(); + __Ownable_init(initialOwner); + __ERC721Burnable_init(); + __UUPSUpgradeable_init(); + } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyOwner + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } +} +` + +export const erc721UUPSRolesBurnablePausableOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC721Upgradeable, ERC721PausableUpgradeable, AccessControlUpgradeable, ERC721BurnableUpgradeable, UUPSUpgradeable { + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address defaultAdmin, address pauser, address upgrader) + public + initializer + { + __ERC721_init("MyToken", "MTK"); + __ERC721Pausable_init(); + __AccessControl_init(); + __ERC721Burnable_init(); + __UUPSUpgradeable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(PAUSER_ROLE, pauser); + _grantRole(UPGRADER_ROLE, upgrader); + } + + function pause() public onlyRole(PAUSER_ROLE) { + _pause(); + } + + function unpause() public onlyRole(PAUSER_ROLE) { + _unpause(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + onlyRole(UPGRADER_ROLE) + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, AccessControlUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +` + +export const erc721UUPSBurnablePausableManagedOptions = (contractName: string) => ` +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.4.0 +pragma solidity ^0.8.27; + +import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract MyToken is Initializable, ERC721Upgradeable, ERC721PausableUpgradeable, AccessManagedUpgradeable, ERC721BurnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialAuthority) public initializer { + __ERC721_init("MyToken", "MTK"); + __ERC721Pausable_init(); + __AccessManaged_init(initialAuthority); + __ERC721Burnable_init(); + __UUPSUpgradeable_init(); + } + + function pause() public restricted { + _pause(); + } + + function unpause() public restricted { + _unpause(); + } + + function _authorizeUpgrade(address newImplementation) + internal + override + restricted + {} + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721Upgradeable, ERC721PausableUpgradeable) + returns (address) + { + return super._update(to, tokenId, auth); + } +} +` + diff --git a/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx index c169b2de0e1..a0db02c86b3 100644 --- a/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx +++ b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx @@ -3,6 +3,8 @@ import './remix-ui-template-explorer-modal.css' import { appActionTypes, AppState } from '@remix-ui/app' import { TemplateExplorerBody } from '../components/template-explorer-body' import { TemplateExplorerContext } from '../../context/template-explorer-context' +import { WizardComponent } from '../components/wizard-component' +import { ContractWizard } from '../components/contract-wizard' export interface RemixUiTemplateExplorerModalProps { dispatch: any @@ -32,7 +34,9 @@ export function RemixUiTemplateExplorerModal (props: RemixUiTemplateExplorerModa
- + {/* */} + {/* */} +
{props.appState.genericModalState.footer && props.appState.genericModalState.footer}
diff --git a/libs/remix-ui/template-explorer-modal/src/utils/contractWizardUtils.tsx b/libs/remix-ui/template-explorer-modal/src/utils/contractWizardUtils.tsx new file mode 100644 index 00000000000..7d7d01eb276 --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/utils/contractWizardUtils.tsx @@ -0,0 +1,540 @@ +import * as erc20 from '../contractCode/erc20' +import * as erc721 from '../contractCode/erc721' +import * as erc1155 from '../contractCode/erc1155' +import { ContractTypeStrategy } from '../../types/template-explorer-types' + +export function getErc20ContractCode (contractType: 'erc20', state: ContractTypeStrategy) { + + if (state.contractType === contractType) { + console.log('state.contractType and contracType are the same') + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSOwnableMintableBurnablePausableOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentMintableBurnablePausableManagedOptions(state.contractName || 'MyToken') + } + return erc20.erc20MintablePausableBurnableOwnableOptions(state.contractName || 'MyToken') + } else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20UUPSRolesFullOptions(state.contractName || 'MyToken') + } + return erc20.erc20MintablePausableBurnableRolesOptions(state.contractName || 'MyToken') + } else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentMintableBurnablePausableManagedOptions(state.contractName || 'MyToken') + } + return erc20.erc20MintablePausableBurnableManagedOptions(state.contractName || 'MyToken') + } + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSOwnableMintableBurnableOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentMintableBurnableManagedOptions(state.contractName || 'MyToken') + } + return erc20.erc20BurnableMintableOwnableOptions(state.contractName || 'MyToken') + } else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20UUPSRolesFullOptions(state.contractName || 'MyToken') + } + } else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentMintableBurnableManagedOptions(state.contractName || 'MyToken') + } + } + return erc20.erc20BurnableMintableOwnableOptions(state.contractName || 'MyToken') + } + if (state.contractOptions.mintable && state.contractOptions.pausable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc20.erc20PausableBurnableMintableOwnableOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentMintableBurnablePausableManagedOptions(state.contractName || 'MyToken') + } + return erc20.erc20MintablePausableOwnableOptions(state.contractName || 'MyToken') + } + } + if (state.contractOptions.burnable && state.contractOptions.pausable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc20.erc20PausableBurnableMintableOwnableOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentMintableBurnablePausableManagedOptions(state.contractName || 'MyToken') + } + } else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20UUPSRolesFullOptions(state.contractName || 'MyToken') + } + return erc20.erc20MintableBurnablePausableRolesOptions(state.contractName || 'MyToken') + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentMintableBurnablePausableManagedOptions(state.contractName || 'MyToken') + } + return erc20.erc20MintableBurnablePausableManagedOptions(state.contractName || 'MyToken') + } + return erc20.erc20MintableBurnablePausableRolesOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSOwnableMintableOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentMintableManagedOptions(state.contractName || 'MyToken') + } + return erc20.erc20MintableOwnableOptions(state.contractName || 'MyToken') + } else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20UUPSRolesFullOptions(state.contractName || 'MyToken') + } + } else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentMintableManagedOptions(state.contractName || 'MyToken') + } + } + return erc20.erc20MintableOwnableOptions(state.contractName || 'MyToken') + } + else if (state.contractOptions.burnable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSOwnableBurnableOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20OwnableBurnableOptions(state.contractName || 'MyToken') + } + } + return erc20.erc20BurnableOwnableOptions(state.contractName || 'MyToken') + } + else if (state.contractOptions.pausable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSOwnablePausableOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentPausableOptions(state.contractName || 'MyToken') + } + } else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20UUPSRolesFullOptions(state.contractName || 'MyToken') + } + return erc20.erc20UUPSOwnablePausableOptions(state.contractName || 'MyToken') + } else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc20.erc20UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc20.erc20TransparentPausableOptions(state.contractName || 'MyToken') + } + } + return erc20.erc20UUPSOwnablePausableOptions(state.contractName || 'MyToken') + } + return erc20.erc20DefaultNoOptions(state.contractName || 'MyToken') + } +} + +export function getErc721ContractCode (contractType: 'erc721', state: ContractTypeStrategy) { + + if (state.contractType === contractType) { + console.log('state.contractType and contracType are the same') + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + console.log('state.contractOptions.mintable and state.contractOptions.burnable and state.contractOptions.pausable are true') + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721PausableBurnableMintableOwnableOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.pausable) { + return erc721.erc721PausableMintableRoleOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721PausableBurnableRoleOptions(state.contractName || 'MyToken') + } + } else if (state.contractUpgradability.transparent) { + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.pausable) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } else if (state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + return erc721.erc721FullOptionsRoles(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.pausable) { + return erc721.erc721PausableMintableRoleOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721PausableBurnableRoleOptions(state.contractName || 'MyToken') + } + return erc721.erc721FullOptionsRolesTransparent(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721FullOptionsRolesTransparent(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + return erc721.erc721FullOptionsRoles(state.contractName || 'MyToken') + } + return erc721.erc721FullOptionsRolesTransparent(state.contractName || 'MyToken') + } + } else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.pausable) { + return erc721.erc721PausableMintableRoleOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721PausableBurnableRoleOptions(state.contractName || 'MyToken') + } + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.pausable) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } else if (state.contractOptions.burnable && state.contractOptions.pausable) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + return erc721.erc721ManagedMintableBurnablePausableOptions(state.contractName || 'MyToken') + } + return erc721.erc721DefaultNoOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsRolesTransparent(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + } + } else if (state.contractOptions.mintable && state.contractOptions.pausable) { //Mintable and Pausable + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSMintablePausableOwnableOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + return erc721.erc721UUPSMintablePausableOwnableOptions(state.contractName || 'MyToken') + } + else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsRolesTransparent(state.contractName || 'MyToken') + } + return erc721.erc721UUPSMintablePausableRolesOptions(state.contractName || 'MyToken') + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + } + return erc721.erc721UUPSMintablePausableManagedOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.burnable && state.contractOptions.pausable) { // Burnable and Pausable + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + return erc721.erc721UUPSBurnablePausableOwnableOptions(state.contractName || 'MyToken') + } + else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsRolesTransparent(state.contractName || 'MyToken') + } + return erc721.erc721UUPSRolesBurnablePausableOptions(state.contractName || 'MyToken') + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + return erc721.erc721UUPSBurnablePausableManagedOptions(state.contractName || 'MyToken') + } + } else if (state.contractOptions.mintable) { // Mintable + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + return erc721.erc721MintableOwnableOptions(state.contractName || 'MyToken') + } + + else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsRolesTransparent(state.contractName || 'MyToken') + } + return erc721.erc721MintableRolesOptions(state.contractName || 'MyToken') + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + return erc721.erc721MintableManagedOptions(state.contractName || 'MyToken') + } + } else if (state.contractOptions.burnable) { // Burnable + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + } else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsRolesTransparent(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + } + } else if (state.contractOptions.pausable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsRolesTransparent(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc721.erc721UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc721.erc721FullOptionsManagedTransparent(state.contractName || 'MyToken') + } + } + } else { + return erc721.erc721DefaultNoOptions(state.contractName || 'MyToken') + } + + return erc721.erc721DefaultNoOptions(state.contractName || 'MyToken') + } +} + +export function getErc1155ContractCode (contractType: 'erc1155', state: ContractTypeStrategy) { + + if (state.contractType === contractType) { + console.log('state.contractType and contracType are the same') + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + return erc1155.erc1155UUPSOwnableMintableBurnablePausableOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + return erc1155.erc1155MintableBurnablePausableOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.pausable) { + return erc1155.erc1155PausableOwnableOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.burnable && state.contractOptions.pausable) { + return erc1155.erc1155PausableBurnableOwnableOptions(state.contractName || 'MyToken') + } + return erc1155.erc1155UUPSOwnableMintableBurnablePausableOptions(state.contractName || 'MyToken') + } + return erc1155.erc1155BurnableOwnableOptions(state.contractName || 'MyToken') + } else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + return erc1155.erc1155UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + return erc1155.erc1155MintableBurnableRolesOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.pausable) { + return erc1155.erc1155MintableBurnableRolesOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.burnable && state.contractOptions.pausable) { + return erc1155.erc1155MintableBurnableRolesOptions(state.contractName || 'MyToken') + } + return erc1155.erc1155MintablePausableBurnableRolesOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + if (state.contractOptions.mintable && state.contractOptions.burnable && state.contractOptions.pausable) { + return erc1155.erc1155UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + return erc1155.erc1155MintablePausableBurnableManagedOptions(state.contractName || 'MyToken') + } + } + } + } else if (state.contractOptions.mintable && state.contractOptions.burnable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + } else if (state.contractOptions.mintable && state.contractOptions.pausable) { // Mintable and Pausable + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + } else if (state.contractOptions.mintable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + } else if (state.contractOptions.burnable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } + return erc1155.erc1155BurnableOptions(state.contractName || 'MyToken') + } else if (state.contractOptions.pausable) { + if (state.contractAccessControl === 'ownable') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSOwnableFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + } else if (state.contractAccessControl === 'roles') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSRolesFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + return erc1155.erc1155PausableRolesOptions(state.contractName || 'MyToken') + } + else if (state.contractAccessControl === 'managed') { + if (state.contractUpgradability.uups) { + return erc1155.erc1155UUPSManagedFullOptions(state.contractName || 'MyToken') + } else if (state.contractUpgradability.transparent) { + return erc1155.erc1155TransparentOwnableFullOptions(state.contractName || 'MyToken') + } + return erc1155.erc1155PausableManagedOptions(state.contractName || 'MyToken') + } + return erc1155.erc1155PausableOwnableOptions(state.contractName || 'MyToken') + } + return erc1155.erc1155DefaultOptions(state.contractName || 'MyToken') + } +} diff --git a/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts b/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts index afeb2d2b92d..28330016d4b 100644 --- a/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts +++ b/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts @@ -114,3 +114,37 @@ export interface TopCardProps { onClick: () => void importWorkspace: boolean } + +export enum ContractWizardAction { + CONTRACT_TYPE_UPDATED = 'CONTRACT_TYPE_UPDATED', + CONTRACT_OPTIONS_UPDATE = 'CONTRACT_OPTIONS_UPDATE', + CONTRACT_ACCESS_CONTROL_UPDATE = 'CONTRACT_ACCESS_CONTROL_UPDATE', + CONTRACT_UPGRADABILITY_UPDATE = 'CONTRACT_UPGRADABILITY_UPDATE', + CONTRACT_CODE_UPDATE = 'CONTRACT_CODE_UPDATE', + CONTRACT_IMPORT_UPDATE = 'CONTRACT_IMPORT_UPDATE', + INITIALIZE_AS_GIT_REPO_UPDATE = 'INITIALIZE_AS_GIT_REPO_UPDATE', + TOKEN_NAME_UPDATE = 'TOKEN_NAME_UPDATE', + CONTRACT_NAME_UPDATE = 'CONTRACT_NAME_UPDATE' +} + +export interface ContractTypeStrategy { + contractType: ContractType + contractOptions: { + mintable?: boolean + burnable?: boolean + pausable?: boolean + } + contractAccessControl: AccessControlType + contractUpgradability: { + uups?: boolean + transparent?: boolean + } + contractCode: string + contractImport?: string + initializeAsGitRepo: boolean + contractName?: string + tokenName?: string +} + +export type AccessControlType = 'ownable' | 'roles' | 'managed' | '' +export type ContractType = 'erc20' | 'erc721' | 'erc1155' | 'custom' From 2203ef06c15b613fafb3c5eeac081f80e1289d0b Mon Sep 17 00:00:00 2001 From: ci-bot Date: Mon, 29 Sep 2025 14:04:12 +0100 Subject: [PATCH 09/15] update types. Working on miniFile Explorer and workspace details --- .../src/components/miniFileExplorer.tsx | 89 ++++++ .../src/components/modifyContract.tsx | 65 +++++ .../src/components/workspaceDetails.tsx | 32 +++ .../src/contractCode/remixDefault.ts | 266 ++++++++++++++++++ .../lib/remix-ui-template-explorer-modal.tsx | 14 +- .../types/template-explorer-types.ts | 15 + 6 files changed, 475 insertions(+), 6 deletions(-) create mode 100644 libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx create mode 100644 libs/remix-ui/template-explorer-modal/src/components/modifyContract.tsx create mode 100644 libs/remix-ui/template-explorer-modal/src/components/workspaceDetails.tsx create mode 100644 libs/remix-ui/template-explorer-modal/src/contractCode/remixDefault.ts diff --git a/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx b/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx new file mode 100644 index 00000000000..b1ff4376147 --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx @@ -0,0 +1,89 @@ +import React from 'react' + +const structure = { + '.deps': { + type: 'folder', + name: '.deps', + isDirectory: true, + isOpen: true, + child: [] + }, + 'contracts': { + type: 'folder', + name: 'contracts', + isDirectory: true, + isOpen: true, + child: [ + { + type: 'file', + name: '1_Storage.sol', + isDirectory: false, + isOpen: true, + child: [] + }, + { + type: 'file', + name: '2_Owner.sol', + isDirectory: false, + isOpen: true, + child: [] + }, + { + type: 'file', + name: '3_Ballot.sol', + isDirectory: false, + isOpen: true, + child: [] + } + ] + }, + 'scripts': { + type: 'folder', + name: 'scripts', + isDirectory: true, + isOpen: true, + child: [] + }, + 'tests': { + type: 'folder', + name: 'tests', + isDirectory: true, + isOpen: true, + child: [] + }, + 'remix.config.json': { + type: 'file', + name: 'remix.config.json', + isDirectory: false, + isOpen: true, + child: [] + } +} + +const g = (n: string) => { + const nw = n.split('.') +} + +export function MiniFileExplorer() { + + return ( +
    + {Object.entries(structure).map(([key, value]) => ( +
  • +
    + + {value.name} +
    + {value.child.map((child) => ( +
  • +
    + + {child.name} +
    +
  • + ))} + + ))} +
+ ) +} diff --git a/libs/remix-ui/template-explorer-modal/src/components/modifyContract.tsx b/libs/remix-ui/template-explorer-modal/src/components/modifyContract.tsx new file mode 100644 index 00000000000..e2e780f6ec2 --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/components/modifyContract.tsx @@ -0,0 +1,65 @@ +import React from 'react' +import { ContractWizardAction, ModifyContractProps } from '../../types/template-explorer-types' + +export function ModifyContract({ tokenName, updateTokenName, strategy, toggleContractOption, switchAccessControl, checkBoxDispatch }: ModifyContractProps) { + const { contractOptions, contractUpgradability, contractAccessControl } = strategy + return ( + <> +
+
+
+
Contract settings
+ + updateTokenName(e.target.value)} /> +
+ +
+
Features
+
+ { + toggleContractOption('mintable')} + } /> + +
+
+ toggleContractOption('burnable')} /> + +
+
+ toggleContractOption('pausable')} /> + +
+
+ +
+
Access control
+
+ switchAccessControl('ownable')} /> + +
+
+ switchAccessControl('roles')} /> + +
+
+ switchAccessControl('managed')} /> + +
+
+ +
+
Upgradability
+
+ checkBoxDispatch({ type: ContractWizardAction.CONTRACT_UPGRADABILITY_UPDATE, payload: { ...contractUpgradability, uups: !contractUpgradability.uups } })} /> + +
+
+ checkBoxDispatch({ type: ContractWizardAction.CONTRACT_UPGRADABILITY_UPDATE, payload: { ...strategy.contractUpgradability, transparent: !strategy.contractUpgradability.transparent } })} /> + +
+
+
+
+ + ) +} diff --git a/libs/remix-ui/template-explorer-modal/src/components/workspaceDetails.tsx b/libs/remix-ui/template-explorer-modal/src/components/workspaceDetails.tsx new file mode 100644 index 00000000000..239206a438e --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/components/workspaceDetails.tsx @@ -0,0 +1,32 @@ +import React from 'react' +import { MiniFileExplorer } from './miniFileExplorer' +import { Editor } from '@monaco-editor/react' +import { ContractTypeStrategy } from '../../types/template-explorer-types' +import { storageContractCode, ownerContractCode, ballotContractCode } from '../contractCode/remixDefault' + +interface WorkspaceDetailsProps { + strategy?: any +} + +export function WorkspaceDetails(props: WorkspaceDetailsProps) { + return ( +
+
+
Workspace Name
+
+
+
+ +
+
+ +
+
+
+ ) +} diff --git a/libs/remix-ui/template-explorer-modal/src/contractCode/remixDefault.ts b/libs/remix-ui/template-explorer-modal/src/contractCode/remixDefault.ts new file mode 100644 index 00000000000..6da58536c48 --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/contractCode/remixDefault.ts @@ -0,0 +1,266 @@ +export const storageContractCode = (contractName: string) => ` +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.8.2 <0.9.0; + +/** + * @title ${contractName} + * @dev Store & retrieve value in a variable + * @custom:dev-run-script ./scripts/deploy_with_ethers.ts + */ +contract ${contractName} { + + uint256 number; + + /** + * @dev Store value in variable + * @param num value to store + */ + function store(uint256 num) public { + number = num; + } + + /** + * @dev Return value + * @return value of 'number' + */ + function retrieve() public view returns (uint256){ + return number; + } +}` + +export const ownerContractCode = (contractName: string) => ` +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +import "hardhat/console.sol"; + +/** + * @title ${contractName} + * @dev Set & change owner + */ +contract ${contractName} { + + address private owner; + + // event for EVM logging + event OwnerSet(address indexed oldOwner, address indexed newOwner); + + // modifier to check if caller is owner + modifier isOwner() { + // If the first argument of 'require' evaluates to 'false', execution terminates and all + // changes to the state and to Ether balances are reverted. + // This used to consume all gas in old EVM versions, but not anymore. + // It is often a good idea to use 'require' to check if functions are called correctly. + // As a second argument, you can also provide an explanation about what went wrong. + require(msg.sender == owner, "Caller is not owner"); + _; + } + + /** + * @dev Set contract deployer as owner + */ + constructor() { + console.log("Owner contract deployed by:", msg.sender); + owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor + emit OwnerSet(address(0), owner); + } + + /** + * @dev Change owner + * @param newOwner address of new owner + */ + function changeOwner(address newOwner) public isOwner { + require(newOwner != address(0), "New owner should not be the zero address"); + emit OwnerSet(owner, newOwner); + owner = newOwner; + } + + /** + * @dev Return owner address + * @return address of owner + */ + function getOwner() external view returns (address) { + return owner; + } +} +` + +export const ballotContractCode = (contractName: string) => ` +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +/** + * @title ${contractName} + * @dev Implements voting process along with vote delegation + */ +contract ${contractName} { + // This declares a new complex type which will + // be used for variables later. + // It will represent a single voter. + struct Voter { + uint weight; // weight is accumulated by delegation + bool voted; // if true, that person already voted + address delegate; // person delegated to + uint vote; // index of the voted proposal + } + + // This is a type for a single proposal. + struct Proposal { + // If you can limit the length to a certain number of bytes, + // always use one of bytes1 to bytes32 because they are much cheaper + bytes32 name; // short name (up to 32 bytes) + uint voteCount; // number of accumulated votes + } + + address public chairperson; + + // This declares a state variable that + // stores a 'Voter' struct for each possible address. + mapping(address => Voter) public voters; + + // A dynamically-sized array of 'Proposal' structs. + Proposal[] public proposals; + + /** + * @dev Create a new ballot to choose one of 'proposalNames'. + * @param proposalNames names of proposals + */ + constructor(bytes32[] memory proposalNames) { + chairperson = msg.sender; + voters[chairperson].weight = 1; + + // For each of the provided proposal names, + // create a new proposal object and add it + // to the end of the array. + for (uint i = 0; i < proposalNames.length; i++) { + // 'Proposal({...})' creates a temporary + // Proposal object and 'proposals.push(...)' + // appends it to the end of 'proposals'. + proposals.push(Proposal({ + name: proposalNames[i], + voteCount: 0 + })); + } + } + + /** + * @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'. + * @param voter address of voter + */ + function giveRightToVote(address voter) external { + // If the first argument of 'require' evaluates + // to 'false', execution terminates and all + // changes to the state and to Ether balances + // are reverted. + // This used to consume all gas in old EVM versions, but + // not anymore. + // It is often a good idea to use 'require' to check if + // functions are called correctly. + // As a second argument, you can also provide an + // explanation about what went wrong. + require( + msg.sender == chairperson, + "Only chairperson can give right to vote." + ); + require( + !voters[voter].voted, + "The voter already voted." + ); + require(voters[voter].weight == 0, "Voter already has the right to vote."); + voters[voter].weight = 1; + } + + /** + * @dev Delegate your vote to the voter 'to'. + * @param to address to which vote is delegated + */ + function delegate(address to) external { + // assigns reference + Voter storage sender = voters[msg.sender]; + require(sender.weight != 0, "You have no right to vote"); + require(!sender.voted, "You already voted."); + + require(to != msg.sender, "Self-delegation is disallowed."); + + // Forward the delegation as long as + // 'to' also delegated. + // In general, such loops are very dangerous, + // because if they run too long, they might + // need more gas than is available in a block. + // In this case, the delegation will not be executed, + // but in other situations, such loops might + // cause a contract to get "stuck" completely. + while (voters[to].delegate != address(0)) { + to = voters[to].delegate; + + // We found a loop in the delegation, not allowed. + require(to != msg.sender, "Found loop in delegation."); + } + + Voter storage delegate_ = voters[to]; + + // Voters cannot delegate to accounts that cannot vote. + require(delegate_.weight >= 1); + + // Since 'sender' is a reference, this + // modifies 'voters[msg.sender]'. + sender.voted = true; + sender.delegate = to; + + if (delegate_.voted) { + // If the delegate already voted, + // directly add to the number of votes + proposals[delegate_.vote].voteCount += sender.weight; + } else { + // If the delegate did not vote yet, + // add to her weight. + delegate_.weight += sender.weight; + } + } + + /** + * @dev Give your vote (including votes delegated to you) to proposal 'proposals[proposal].name'. + * @param proposal index of proposal in the proposals array + */ + function vote(uint proposal) external { + Voter storage sender = voters[msg.sender]; + require(sender.weight != 0, "Has no right to vote"); + require(!sender.voted, "Already voted."); + sender.voted = true; + sender.vote = proposal; + + // If 'proposal' is out of the range of the array, + // this will throw automatically and revert all + // changes. + proposals[proposal].voteCount += sender.weight; + } + + /** + * @dev Computes the winning proposal taking all previous votes into account. + * @return winningProposal_ index of winning proposal in the proposals array + */ + function winningProposal() public view + returns (uint winningProposal_) + { + uint winningVoteCount = 0; + for (uint p = 0; p < proposals.length; p++) { + if (proposals[p].voteCount > winningVoteCount) { + winningVoteCount = proposals[p].voteCount; + winningProposal_ = p; + } + } + } + + /** + * @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then + * @return winnerName_ the name of the winner + */ + function winnerName() external view + returns (bytes32 winnerName_) + { + winnerName_ = proposals[winningProposal()].name; + } +}` diff --git a/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx index a0db02c86b3..bcde1593009 100644 --- a/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx +++ b/libs/remix-ui/template-explorer-modal/src/lib/remix-ui-template-explorer-modal.tsx @@ -1,10 +1,10 @@ -import React, { useContext } from 'react' +import React, { useContext, useReducer } from 'react' import './remix-ui-template-explorer-modal.css' import { appActionTypes, AppState } from '@remix-ui/app' -import { TemplateExplorerBody } from '../components/template-explorer-body' import { TemplateExplorerContext } from '../../context/template-explorer-context' -import { WizardComponent } from '../components/wizard-component' import { ContractWizard } from '../components/contract-wizard' +import { WorkspaceDetails } from '../components/workspaceDetails' +import { initialState, templateExplorerReducer } from '../../reducers/template-explorer-reducer' export interface RemixUiTemplateExplorerModalProps { dispatch: any @@ -15,6 +15,7 @@ export interface RemixUiTemplateExplorerModalProps { export function RemixUiTemplateExplorerModal (props: RemixUiTemplateExplorerModalProps) { const { plugin, setSearchTerm } = useContext(TemplateExplorerContext) + const [state, dispatch] = useReducer(templateExplorerReducer, initialState) return (
@@ -36,10 +37,11 @@ export function RemixUiTemplateExplorerModal (props: RemixUiTemplateExplorerModa
{/* */} {/* */} - -
+ {/* */} + + {/*
{props.appState.genericModalState.footer && props.appState.genericModalState.footer} -
+
*/}
diff --git a/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts b/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts index 28330016d4b..958a16da01d 100644 --- a/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts +++ b/libs/remix-ui/template-explorer-modal/types/template-explorer-types.ts @@ -148,3 +148,18 @@ export interface ContractTypeStrategy { export type AccessControlType = 'ownable' | 'roles' | 'managed' | '' export type ContractType = 'erc20' | 'erc721' | 'erc1155' | 'custom' + +export interface ContractOptions {mintable: boolean, burnable: boolean, pausable: boolean} +export interface ContractUpgradability {uups: boolean, transparent: boolean} + +export interface ModifyContractProps { + tokenName: string + updateTokenName: (tokenName: string) => void + strategy: ContractTypeStrategy & {contractOptions: ContractOptions, contractUpgradability: ContractUpgradability} + toggleContractOption: (key: keyof ContractOptions) => void + switchAccessControl: (accessControl: AccessControlType) => void + checkBoxDispatch: (value: { + type: ContractWizardAction; + payload: any; +}) => void +} From 49177277090a915de32797d60c6b2758aece0a79 Mon Sep 17 00:00:00 2001 From: ci-bot Date: Mon, 29 Sep 2025 17:36:00 +0100 Subject: [PATCH 10/15] fix dom element nesting error --- .../src/components/miniFileExplorer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx b/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx index b1ff4376147..74913594a20 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx @@ -75,12 +75,12 @@ export function MiniFileExplorer() { {value.name}
{value.child.map((child) => ( -
  • +
    {child.name}
    -
  • + ))} ))} From 06f23095426133d767bf2e92b2eb8f8052e8639b Mon Sep 17 00:00:00 2001 From: ci-bot Date: Mon, 29 Sep 2025 18:28:38 +0100 Subject: [PATCH 11/15] styling icons --- .../src/components/miniFileExplorer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx b/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx index 74913594a20..a19fd9eda96 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx @@ -70,14 +70,14 @@ export function MiniFileExplorer() {
      {Object.entries(structure).map(([key, value]) => (
    • -
      +
      {value.name}
      {value.child.map((child) => (
      - + {child.name}
      From 268d7268e9260ddef257a25b53c0dba76a28fc18 Mon Sep 17 00:00:00 2001 From: ci-bot Date: Tue, 30 Sep 2025 10:31:42 +0100 Subject: [PATCH 12/15] fix styling of editor. fix styling of miniexplorer --- .../src/components/miniFileExplorer.tsx | 45 ++++++++++++------- .../src/components/workspaceDetails.tsx | 24 +++++++--- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx b/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx index a19fd9eda96..7818baa50ba 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/miniFileExplorer.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useState } from 'react' const structure = { '.deps': { @@ -6,7 +6,8 @@ const structure = { name: '.deps', isDirectory: true, isOpen: true, - child: [] + child: [], + selected: false }, 'contracts': { type: 'folder', @@ -19,21 +20,24 @@ const structure = { name: '1_Storage.sol', isDirectory: false, isOpen: true, - child: [] + child: [], + selected: false }, { type: 'file', name: '2_Owner.sol', isDirectory: false, isOpen: true, - child: [] + child: [], + selected: false }, { type: 'file', name: '3_Ballot.sol', isDirectory: false, isOpen: true, - child: [] + child: [], + selected: false } ] }, @@ -42,42 +46,53 @@ const structure = { name: 'scripts', isDirectory: true, isOpen: true, - child: [] + child: [], + selected: false }, 'tests': { type: 'folder', name: 'tests', isDirectory: true, isOpen: true, - child: [] + child: [], + selected: false }, 'remix.config.json': { type: 'file', name: 'remix.config.json', isDirectory: false, isOpen: true, - child: [] + child: [], + selected: false } } -const g = (n: string) => { - const nw = n.split('.') +const getFileExtension = (fileName: string) => { + const nw = fileName.split('.') + return nw[nw.length - 1] } +const styleJson = (child: any) => getFileExtension(child.name) === 'json' ? '#fb923c' : '' + +const styleSelected = (child: any) => child.selected ? 'bg-secondary' : '' export function MiniFileExplorer() { + const [selectedStyle, setSelectedStyle] = useState('') return ( -
        +
          {Object.entries(structure).map(([key, value]) => (
        • - + {value.name}
          - {value.child.map((child) => ( + {value.child.map((child: any, index: number) => ( -
          - +
          { + setSelectedStyle(child.selected ? '' : 'bg-secondary') + }}> + {child.name}
          diff --git a/libs/remix-ui/template-explorer-modal/src/components/workspaceDetails.tsx b/libs/remix-ui/template-explorer-modal/src/components/workspaceDetails.tsx index 239206a438e..30dc46b4969 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/workspaceDetails.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/workspaceDetails.tsx @@ -10,19 +10,29 @@ interface WorkspaceDetailsProps { export function WorkspaceDetails(props: WorkspaceDetailsProps) { return ( -
          -
          -
          Workspace Name
          +
          +
          + Workspace Name +
          -
          -
          +
          +
          -
          +
          From 191337b4f0d77bf871a25892311d9e81590989f3 Mon Sep 17 00:00:00 2001 From: ci-bot Date: Tue, 7 Oct 2025 01:14:22 +0100 Subject: [PATCH 13/15] connect screens statefully. update zeppelin wizard code --- .../context/template-explorer-context.tsx | 16 +- .../reducers/template-explorer-reducer.tsx | 41 +++-- .../src/components/contract-wizard.tsx | 2 +- .../components/generateWorkspaceWithAi.tsx | 22 +++ .../components/genericWorkspaceTemplate.tsx | 19 +++ .../src/components/template-explorer-body.tsx | 8 +- .../src/components/template-explorer.tsx | 29 +++- .../src/components/workspaceDetails.tsx | 1 + .../src/contractCode/erc721.ts | 150 +++++++++++++----- .../lib/remix-ui-template-explorer-modal.tsx | 37 +++-- .../src/utils/contractWizardUtils.tsx | 2 + .../src/utils/wizardStepHandler.tsx | 3 + .../stategies/templateCategoryStrategy.ts | 59 +++++++ .../types/template-explorer-types.ts | 10 +- 14 files changed, 322 insertions(+), 77 deletions(-) create mode 100644 libs/remix-ui/template-explorer-modal/src/components/generateWorkspaceWithAi.tsx create mode 100644 libs/remix-ui/template-explorer-modal/src/components/genericWorkspaceTemplate.tsx create mode 100644 libs/remix-ui/template-explorer-modal/src/utils/wizardStepHandler.tsx create mode 100644 libs/remix-ui/template-explorer-modal/stategies/templateCategoryStrategy.ts diff --git a/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx b/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx index 826d2c19665..73a5a2b1acb 100644 --- a/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx +++ b/libs/remix-ui/template-explorer-modal/context/template-explorer-context.tsx @@ -26,8 +26,11 @@ export const TemplateExplorerProvider = (props: { plugin: TemplateExplorerModalP dispatch({ type: TemplateExplorerWizardAction.SET_METADATA, payload: metadata }) }, []) + useEffect(() => { + console.log('state context', state) + }, [state]) + const setSearchTerm = (term: string) => { - console.log('check status', { term, dedupedTemplates, state }) dispatch({ type: TemplateExplorerWizardAction.SET_SEARCH_TERM, payload: term }) } @@ -126,7 +129,14 @@ export const TemplateExplorerProvider = (props: { plugin: TemplateExplorerModalP return (filteredTemplates || []).map((group: any) => ({ ...group, items: makeUniqueItems(group && group.items ? group.items : []) - })).filter((g: any) => g && g.items && g.items.length > 0) + })).filter((g: any) => { + // Keep categories that have items OR special functionality (like Cookbook) + return g && ( + (g.items && g.items.length > 0) || + (g.name === 'Cookbook' && g.onClick) || + (g.hasOptions && g.name !== 'Cookbook') + ) + }) }, [filteredTemplates, recentTemplates]) const handleTagClick = (tag: string) => { @@ -153,7 +163,7 @@ export const TemplateExplorerProvider = (props: { plugin: TemplateExplorerModalP } } - const contextValue = { templateRepository: state.templateRepository, metadata: state.metadata, selectedTag: state.selectedTag, recentTemplates, filteredTemplates, dedupedTemplates, handleTagClick, clearFilter, addRecentTemplate, RECENT_KEY, allTags, plugin, setSearchTerm } + const contextValue = { templateRepository: state.templateRepository, metadata: state.metadata, selectedTag: state.selectedTag, recentTemplates, filteredTemplates, dedupedTemplates, handleTagClick, clearFilter, addRecentTemplate, RECENT_KEY, allTags, plugin, setSearchTerm, dispatch, state } return ( diff --git a/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx b/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx index e962dee9cb2..9f75c9a610c 100644 --- a/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx +++ b/libs/remix-ui/template-explorer-modal/reducers/template-explorer-reducer.tsx @@ -1,11 +1,11 @@ import React from 'react' -import { MetadataType, TemplateExplorerWizardAction, TemplateExplorerWizardState, TemplateRepository } from '../types/template-explorer-types' +import { MetadataType, TemplateExplorerWizardAction, TemplateExplorerWizardState, TemplateRepository, WizardStep } from '../types/template-explorer-types' import { metadata, templatesRepository } from '../src/utils/helpers' export const initialState: TemplateExplorerWizardState = { workspaceTemplateChosen: '', workspaceTemplateGroupChosen: '', - workspaceName: '', + workspaceName: 'workspace Name', defaultWorkspaceName: '', topLeftNagivationName: '', initializeAsGitRepo: false, @@ -14,7 +14,10 @@ export const initialState: TemplateExplorerWizardState = { metadata: metadata as MetadataType, templateRepository: templatesRepository as TemplateRepository || [], selectedTag: null, - setSearchTerm: (term: string) => {} + setSearchTerm: (term: string) => {}, + wizardStep: 'template', + setWizardStep: (step: WizardStep) => {}, + recentBump: 0 } export const templateExplorerReducer = (state: TemplateExplorerWizardState, action: any) => { @@ -23,31 +26,41 @@ export const templateExplorerReducer = (state: TemplateExplorerWizardState, acti return { ...state, templateRepository: action.payload } case TemplateExplorerWizardAction.SET_METADATA: return { ...state, metadata: action.payload } - case TemplateExplorerWizardAction.SELECT_TEMPLATE: - return action.payload - case TemplateExplorerWizardAction.SET_WORKSPACE_TEMPLATE_GROUP: - return action.payload - case TemplateExplorerWizardAction.SET_WORKSPACE_NAME: - return action.payload + case TemplateExplorerWizardAction.SELECT_TEMPLATE:{ + return { ...state, workspaceTemplateChosen: action.payload } + } + case TemplateExplorerWizardAction.SET_WORKSPACE_TEMPLATE_GROUP:{ + return { ...state, workspaceTemplateGroupChosen: action.payload.templateGroupChosen } + } + case TemplateExplorerWizardAction.SET_WORKSPACE_NAME:{ + return { ...state, workspaceName: action.payload } + } case TemplateExplorerWizardAction.SET_DEFAULT_WORKSPACE_NAME: - return action.payload + return { ...state, defaultWorkspaceName: action.payload } case TemplateExplorerWizardAction.SET_TOP_LEFT_NAVIGATION_NAME: - return action.payload + return { ...state, topLeftNagivationName: action.payload } case TemplateExplorerWizardAction.SET_INITIALIZE_AS_GIT_REPO: - return action.payload + return { ...state, initializeAsGitRepo: action.payload } case TemplateExplorerWizardAction.SET_WORKSPACE_GENERATED_WITH_AI: - return action.payload + return { ...state, workspaceGeneratedWithAi: action.payload } case TemplateExplorerWizardAction.END_WORKSPACE_WIZARD: - return action.payload + return { ...state, wizardStep: 'finishSetup' } case TemplateExplorerWizardAction.SET_SELECTED_TAG: { return { ...state, selectedTag: action.payload } } + case TemplateExplorerWizardAction.SET_RECENT_BUMP: { + return { ...state, recentBump: action.payload } + } case TemplateExplorerWizardAction.CLEAR_SELECTED_TAG: { return { ...state, selectedTag: null } } case TemplateExplorerWizardAction.SET_SEARCH_TERM: { return { ...state, searchTerm: action.payload } } + case TemplateExplorerWizardAction.SET_WIZARD_STEP: { + console.log('action.payload wizardStep', action.payload) + return { ...state, wizardStep: action.payload } + } default: return state } diff --git a/libs/remix-ui/template-explorer-modal/src/components/contract-wizard.tsx b/libs/remix-ui/template-explorer-modal/src/components/contract-wizard.tsx index f404d5452a6..9ee7f8939cc 100644 --- a/libs/remix-ui/template-explorer-modal/src/components/contract-wizard.tsx +++ b/libs/remix-ui/template-explorer-modal/src/components/contract-wizard.tsx @@ -153,7 +153,7 @@ export function ContractWizard () {
          diff --git a/libs/remix-ui/template-explorer-modal/src/components/generateWorkspaceWithAi.tsx b/libs/remix-ui/template-explorer-modal/src/components/generateWorkspaceWithAi.tsx new file mode 100644 index 00000000000..259227e3771 --- /dev/null +++ b/libs/remix-ui/template-explorer-modal/src/components/generateWorkspaceWithAi.tsx @@ -0,0 +1,22 @@ +import React, { useReducer } from 'react' +import { TemplateExplorerWizardAction } from '../../types/template-explorer-types' +import { initialState, templateExplorerReducer } from '../../reducers/template-explorer-reducer' + +export function GenerateWorkspaceWithAi() { + const [state, dispatch] = useReducer(templateExplorerReducer, initialState) + return ( +
          +
          +
          + +
          +
          +