Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6,001 changes: 3,236 additions & 2,765 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
"@mui/x-data-grid": "^5.17.11",
"@mui/x-data-grid-generator": "^5.17.11",
"@terran-one/cw-simulate": "^2.8.4",
"@rjsf/core": "^5.0.0-beta.14",
"@rjsf/mui": "^5.0.0-beta.15",
"@rjsf/utils": "^5.0.0-beta.14",
"@rjsf/validator-ajv8": "^5.0.0-beta.14",
"@terran-one/react-diff-viewer": "^3.1.1",
"@uiw/react-codemirror": "^4.14.2",
"axios": "^1.2.0",
Expand Down
42 changes: 38 additions & 4 deletions src/CWSimulationBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,21 @@ type WatcherState<T> = {
export type WatcherComparator<T = unknown> = (last: T, curr: T) => boolean;
export type WatcherCommitter<T = unknown> = (raw: T) => T;

export type AccountEx = ReturnType<CWSimulationBridge["getAccounts"]>[string];
export type AccountEx = ReturnType<CWSimulationBridge['getAccounts']>[string];
export type FileUploadType = {
name: string;
schema: SchemaType;
content: Buffer | JSON;
};

export type SchemaType ={
name:string;
content:JSON;
}

export type CodeInfoEx = CodeInfo & {
name?: string;
schema?: SchemaType;
hidden?: boolean;
};

Expand Down Expand Up @@ -133,19 +144,30 @@ export default class CWSimulationBridge {
}

/** Store a new smart contract code in the simulation & re-sync bridge. */
storeCode(sender: string, name: string, content: Buffer, funds: Coin[] = []) {
const codeId = this.app.wasm.create(sender, content);
storeCode(sender: string, fileUpload: FileUploadType, funds: Coin[] = []) {
const codeId = this.app.wasm.create(sender, fileUpload.content as Buffer);

// inject contract name for convenient lookup.
this.codes.tx((setter) => {
setter(codeId, "name")(name);
setter(codeId, "name")(fileUpload.name);
setter(codeId, "schema")(fileUpload.schema);
return Ok(undefined);
});

this.sync();
return codeId;
}

storeSchema(codeId: number, fileUpload: FileUploadType) {
const code = this.getCode(codeId);
if (!code) return;
this.codes.tx((setter) => {
setter(codeId, "schema")(fileUpload.schema);
return Ok(undefined);
});
this.sync();
}

/** Hide a contract from the UI - it is not actually deleted - and re-sync bridge. */
hideCode(codeId: number) {
this.codes.tx((setter) => {
Expand All @@ -156,6 +178,18 @@ export default class CWSimulationBridge {
return this;
}

/**
* Get contract schema for a given contract address.
* @param address
*/
getSchema(address: string) {
const contract = this.getContract(address);
if (!contract) return;
const code = this.getCode(contract.codeId);
if (!code) return;
return Object.assign({ schema: code.schema }, { name: code.name });
}

/** Get contract associated with given address, and augment contract info with same address for convenience. */
getContract(address: string) {
const contract = this.contracts.getObject(address);
Expand Down
102 changes: 77 additions & 25 deletions src/components/drawer/ContractsSubMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from "@mui/material";
import type { Coin } from "@terran-one/cw-simulate";
import { useSetAtom } from "jotai";
import { useCallback, useMemo, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useNotification } from "../../atoms/snackbarNotificationState";
import { drawerSubMenuState } from "../../atoms/uiState";
Expand All @@ -24,17 +24,27 @@ import UploadModal from "../upload/UploadModal";
import SubMenuHeader from "./SubMenuHeader";
import T1MenuItem from "./T1MenuItem";
import useSimulation from "../../hooks/useSimulation";
import { AccountEx, useAccounts, useCode, useCodes } from "../../CWSimulationBridge";
import {
AccountEx,
useAccounts,
useCode,
useCodes,
} from "../../CWSimulationBridge";
import { downloadWasm } from "../../utils/fileUtils";
import Funds from "../Funds";
import SchemaIcon from "@mui/icons-material/Schema";
import useDebounce from "../../hooks/useDebounce";
import { useBind } from "../../utils/reactUtils";
import Accounts from "../Accounts";
import { BeautifyJSON } from "../simulation/tabs/Common";
import useMuiTheme from "@mui/material/styles/useTheme";
import DialogButton from "../DialogButton";
import ConfirmDialog, { ConfirmDeleteDialog, ConfirmDialogProps } from "../dialogs/ConfirmDialog";
import ConfirmDialog, {
ConfirmDeleteDialog,
ConfirmDialogProps,
} from "../dialogs/ConfirmDialog";
import T1Dialog, { T1DialogAPI } from "../dialogs/T1Dialog";
import { SchemaForm } from "../simulation/SchemaForm";

export interface IContractsSubMenuProps {}

Expand Down Expand Up @@ -89,17 +99,24 @@ function CodeMenuItem({ codeId }: ICodeMenuItemProps) {
const setNotification = useNotification();
const code = useCode(sim, codeId)!;

const [openInstantiate, setOpenInstantiate] = useState(false);
const [openUploadDialog, setOpenUploadDialog] = useState(false);
const [openDelete, setOpenDelete] = useState(false);
const schema = code.schema;
const download = useCallback(() => {
downloadWasm(code.wasmCode, code.name ?? "<unnamed code>");
}, [code]);

const handleDelete = useCallback(() => {
sim.hideCode(code.codeId);
setNotification('Successfully deleted contract');
setNotification("Successfully deleted contract");
}, [code]);

const MyInstantiateDialog = useBind(InstantiateDialog, { codeId });
const MyConfirmDeleteDialog = useBind(ConfirmDeleteDialog, { noun: 'contract', onConfirm: handleDelete });
const MyConfirmDeleteDialog = useBind(ConfirmDeleteDialog, {
noun: "contract",
onConfirm: handleDelete,
});

return (
<T1MenuItem
Expand All @@ -110,7 +127,9 @@ function CodeMenuItem({ codeId }: ICodeMenuItemProps) {
key="instantiate"
Component={MenuItem}
DialogComponent={MyInstantiateDialog}
onClose={() => {close()}}
onClose={() => {
close();
}}
>
<ListItemIcon>
<RocketLaunchIcon />
Expand All @@ -136,7 +155,29 @@ function CodeMenuItem({ codeId }: ICodeMenuItemProps) {
</ListItemIcon>
<ListItemText>Delete</ListItemText>
</DialogButton>,
<MenuItem key="schema" onClick={() => setOpenUploadDialog(true)}>
<ListItemIcon>
<SchemaIcon />
</ListItemIcon>
<ListItemText>Upload schema</ListItemText>
</MenuItem>,
]}
optionsExtras={({ close }) => (
<>
<UploadModal
variant="schema"
existingFileName={schema?.name}
codeId={codeId}
open={openUploadDialog}
onClose={() => {
setOpenUploadDialog(false);
close();
}}
dropTitle="Upload Schema"
dropzoneText="Upload or drop a schema file here"
/>
</>
)}
/>
);
}
Expand All @@ -147,10 +188,7 @@ interface IInstantiateDialogProps {
onClose(): void;
}

function InstantiateDialog({
codeId,
...props
}: IInstantiateDialogProps) {
function InstantiateDialog({ codeId, ...props }: IInstantiateDialogProps) {
const theme = useMuiTheme();
const sim = useSimulation();
const navigate = useNavigate();
Expand All @@ -159,6 +197,9 @@ function InstantiateDialog({
const accounts = useAccounts(sim);
const defaultAccount = Object.values(accounts)[0] || "";
const [isJsonValid, setIsJsonValid] = useState(true);
const schema = code.schema;
// @ts-ignore
const instantiateSchema = schema ? schema.content.instantiate : {};
const setDrawerSubMenu = useSetAtom(drawerSubMenuState);

const [funds, setFunds] = useState<Coin[]>([]);
Expand All @@ -171,7 +212,7 @@ function InstantiateDialog({
const placeholder = {
count: 0,
};

useEffect(() => {}, []);
const handleLabelChange = useDebounce(
() => {
const val = ref.current?.value.trim();
Expand All @@ -198,31 +239,34 @@ function InstantiateDialog({
funds,
instancelabel
);

navigate(`/instances/${contract.address}`);
finish();
setDrawerSubMenu(undefined);
}
catch (e: any) {
} catch (e: any) {
setNotification(`Unable to instantiate with error: ${e.message}`, {
severity: "error",
});
console.error(e);
}
};

const ConfirmCloseDialog = useCallback((props: ConfirmDialogProps) => (
<ConfirmDialog
{...props}
message='Are you sure you want to cancel contract instantiation?'
/>
), []);

const ConfirmCloseDialog = useCallback(
(props: ConfirmDialogProps) => (
<ConfirmDialog
{...props}
message="Are you sure you want to cancel contract instantiation?"
/>
),
[]
);

return (
<T1Dialog
{...props}
confirmClose
title='Instantiate Contract'
actions={api => (
title="Instantiate Contract"
actions={(api) => (
<>
<Button variant="outlined" onClick={() => api.cancel()}>
Cancel
Expand All @@ -238,13 +282,16 @@ function InstantiateDialog({
)}
ConfirmCloseDialogComponent={ConfirmCloseDialog}
sx={{
'.MuiDialogTitle-root+.MuiDialogContent-root': {
".MuiDialogTitle-root+.MuiDialogContent-root": {
pt: 1,
},
}}
>
<DialogContent>
<Accounts defaultAccount={defaultAccount.address} onChange={setAccount} />
<Accounts
defaultAccount={defaultAccount.address}
onChange={setAccount}
/>
<Funds
TextComponent={DialogContentText}
onChange={setFunds}
Expand All @@ -260,14 +307,19 @@ function InstantiateDialog({
sx={{ mt: 2 }}
/>
</DialogContent>

<DialogContent>
<Grid
container
sx={{ alignItems: "center", justifyContent: "space-between" }}
>
<DialogContentText>InstantiateMsg</DialogContentText>
<Grid item>
<SchemaForm
schema={instantiateSchema}
submit={setPayload}
iconColor={theme.palette.common.black}
/>
<BeautifyJSON
onChange={setPayload}
disabled={!payload.length || !isJsonValid}
Expand Down
Loading