Skip to content

Commit

Permalink
Merge pull request #80 from blocto/feat/evm-batch-tx-panel
Browse files Browse the repository at this point in the history
Feat/evm batch tx editor
  • Loading branch information
q20274982 authored Jan 9, 2024
2 parents 3018efb + 035e585 commit c634065
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 83 deletions.
15 changes: 9 additions & 6 deletions src/components/EvmEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import EvmSignEditor from "./EvmEditors/EvmSignEditor";
import EvmUserOpEditor from "./EvmEditors/EvmUserOpEditor";
import EvmSendEditor from "./EvmEditors/EvmSendEditor";
import EvmContractEditor from "./EvmEditors/EvmContractEditor";
import EvmBatchTxEditor from "./EvmEditors/EvmBatchTxEditor";
import type { EthereumTypes } from "@blocto/sdk";
import { bloctoSDK, useEthereum, supportedChains, web3 } from "../services/evm";
import ReactJson from "react-json-view";
Expand Down Expand Up @@ -233,6 +234,7 @@ const EvmEditor = (): ReactJSXElement => {
<Tab>User Operation</Tab>
<Tab>Send</Tab>
<Tab>Contract</Tab>
<Tab>Batch Transaction</Tab>
</TabList>
<TabPanels>
<TabPanel>
Expand All @@ -254,12 +256,7 @@ const EvmEditor = (): ReactJSXElement => {
</TabPanel>
<TabPanel>
<EvmSendEditor
setRequestObject={(params = []) =>
setRequestObject({
method: "eth_sendTransaction",
params,
})
}
setRequestObject={setRequestObject}
account={account}
/>
</TabPanel>
Expand All @@ -271,6 +268,12 @@ const EvmEditor = (): ReactJSXElement => {
chainId={chainId}
/>
</TabPanel>
<TabPanel>
<EvmBatchTxEditor
setRequestObject={setRequestObject}
account={account}
/>
</TabPanel>
</TabPanels>
</Tabs>
</Flex>
Expand Down
111 changes: 111 additions & 0 deletions src/components/EvmEditors/EvmBatchTxEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React, { useEffect, useState, Dispatch, SetStateAction } from "react";
import {
Box,
Text,
Grid,
Flex,
IconButton,
Radio,
RadioGroup,
} from "@chakra-ui/react";
import { AddIcon } from "@chakra-ui/icons";
import { ReactJSXElement } from "@emotion/react/types/jsx-namespace";
import type { EthereumTypes } from "@blocto/sdk";
import EvmTxForm from "./EvmTxForm";

interface EvmBatchTxEditorProps {
setRequestObject: Dispatch<
SetStateAction<EthereumTypes.EIP1193RequestPayload | undefined>
>;
account: string | null;
}

const RevertOptionMap: Record<string, any> = {
true: true,
false: false,
unset: undefined,
};
const emptyTx = {};

const EvmBatchTxEditor = ({
setRequestObject,
account,
}: EvmBatchTxEditorProps): ReactJSXElement => {
const [revert, setRevert] = useState<string>("true");
const [txs, setTxs] = useState<any[]>([emptyTx]);

useEffect(() => {
if (account) {
setRequestObject({
method: "wallet_sendMultiCallTransaction",
params: [
txs,
...(RevertOptionMap[revert] !== undefined
? [RevertOptionMap[revert]]
: []),
],
});
}
}, [account, setRequestObject, revert, txs]);

return (
<>
<Grid templateRows="repeat(4, min-content)" gap="10px">
<Box fontWeight="bold">Revert</Box>
<RadioGroup
value={revert}
onChange={(e) => {
setRevert(e);
}}
>
<Flex gap="15px">
{Object.keys(RevertOptionMap).map((key) => (
<Radio key={key} value={key}>
{key}
</Radio>
))}
</Flex>
</RadioGroup>

<Flex>
<Box fontWeight="bold">Transaction</Box>
<IconButton
ml={2}
aria-label="Add Transaction"
isRound
icon={<AddIcon />}
size="xs"
colorScheme="blue"
onClick={() => {
setTxs((prev) => [...prev, emptyTx]);
}}
/>
</Flex>
<Flex flexDir="column" mt={2} pl={4}>
{txs.map((value, i) => (
<Box key={i}>
<Text fontWeight="bold" mb={2}>
Transaction {i + 1}
</Text>
<Flex my="5px" alignItems="center">
<EvmTxForm
key={i}
setTransactionObject={(tx) => {
setTxs((prev) => {
const newTxs = [...prev];
newTxs[i] = tx;
return newTxs;
});
}}
account={account}
/>
</Flex>
</Box>
))}
</Flex>
</Grid>
</>
);
};

export default EvmBatchTxEditor;
83 changes: 13 additions & 70 deletions src/components/EvmEditors/EvmSendEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,84 +1,27 @@
import React, { useEffect, useState, Dispatch } from "react";
import { Box, Textarea, Grid } from "@chakra-ui/react";
import React, { Dispatch, useCallback } from "react";
import { ReactJSXElement } from "@emotion/react/types/jsx-namespace";
import type { EthereumTypes } from "@blocto/sdk";
import { web3 } from "../../services/evm";
import EvmTxForm from "./EvmTxForm";

const EvmSendEditor = ({
setRequestObject,
account,
}: {
setRequestObject: Dispatch<
EthereumTypes.EIP1193RequestPayload["params"] | undefined
>;
setRequestObject: Dispatch<EthereumTypes.EIP1193RequestPayload | undefined>;
account: string | null;
}): ReactJSXElement => {
const [fromString, setFrom] = useState<string>(account || "");
const [toString, setTo] = useState<string>("");
const [valueString, setValue] = useState<string>("");
const [dataString, setData] = useState<string>("");
useEffect(() => {
if (account) {
const sendObj: {
from: string;
to?: string;
value?: string;
data?: string;
} = {
from: fromString,
};
if (toString) {
sendObj.to = toString;
}
if (valueString) {
sendObj.value = web3.utils.toHex(valueString);
}
if (dataString) {
sendObj.data = dataString;
}
setRequestObject([sendObj]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [account, fromString, toString, dataString, valueString]);
useEffect(() => {
setFrom(account || "");
}, [account]);
const setTransactionObject = useCallback(
(params: EthereumTypes.EIP1193RequestPayload["params"] | undefined) => {
setRequestObject({
method: "eth_sendTransaction",
params,
});
},
[setRequestObject]
);

return (
<Grid templateColumns="min-content 1fr" alignItems="center" gap={6}>
<Box mx="10px">From:</Box>
<Textarea
rows={1}
value={fromString}
onChange={(e) => {
setFrom(e.target.value);
}}
/>
<Box mx="10px">To:</Box>
<Textarea
rows={1}
value={toString}
onChange={(e) => {
setTo(e.target.value);
}}
/>
<Box mx="10px">Value:</Box>
<Textarea
rows={1}
value={valueString}
onChange={(e) => {
setValue(e.target.value);
}}
/>
<Box mx="10px">Data:</Box>
<Textarea
rows={3}
value={dataString}
onChange={(e) => {
setData(e.target.value);
}}
/>
</Grid>
<EvmTxForm setTransactionObject={setTransactionObject} account={account} />
);
};

Expand Down
93 changes: 93 additions & 0 deletions src/components/EvmEditors/EvmTxForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, { useEffect, useState, Dispatch } from "react";
import { Box, Textarea, Grid } from "@chakra-ui/react";
import { ReactJSXElement } from "@emotion/react/types/jsx-namespace";
import type { EthereumTypes } from "@blocto/sdk";
import { web3 } from "../../services/evm";

interface EvmTxFormProps {
setTransactionObject: Dispatch<
EthereumTypes.EIP1193RequestPayload["params"] | undefined
>;
account: string | null;
}

const EvmTxForm = ({
setTransactionObject,
account,
}: EvmTxFormProps): ReactJSXElement => {
const [fromString, setFrom] = useState<string>(account || "");
const [toString, setTo] = useState<string>("");
const [valueString, setValue] = useState<string>("");
const [dataString, setData] = useState<string>("");

useEffect(() => {
if (account) {
const sendObj: {
from: string;
to?: string;
value?: string;
data?: string;
} = {
from: fromString,
};
if (toString) {
sendObj.to = toString;
}
if (valueString) {
sendObj.value = web3.utils.toHex(valueString);
}
if (dataString) {
sendObj.data = dataString;
}
setTransactionObject([sendObj]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [account, fromString, toString, dataString, valueString]);
useEffect(() => {
setFrom(account || "");
}, [account]);

return (
<Grid
templateColumns="min-content 1fr"
alignItems="center"
gap={6}
width="100%"
>
<Box mx="10px">From:</Box>
<Textarea
rows={1}
value={fromString}
onChange={(e) => {
setFrom(e.target.value);
}}
/>
<Box mx="10px">To:</Box>
<Textarea
rows={1}
value={toString}
onChange={(e) => {
setTo(e.target.value);
}}
/>
<Box mx="10px">Value:</Box>
<Textarea
rows={1}
value={valueString}
onChange={(e) => {
setValue(e.target.value);
}}
/>
<Box mx="10px">Data:</Box>
<Textarea
rows={3}
value={dataString}
onChange={(e) => {
setData(e.target.value);
}}
/>
</Grid>
);
};

export default EvmTxForm;
9 changes: 2 additions & 7 deletions src/components/EvmEditors/EvmUserOpEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import { EthereumTypes } from "@blocto/sdk";
import ParamEditor from "./ParamEditor";
import * as UserOperationTemplate from "../../scripts/evm/UserOperation";
import type { IUserOperationTemplate } from "../../scripts/evm/UserOperation";
import EvmSendEditor from "./EvmSendEditor";
import { AbiItem, numberToHex, isAddress, isHexStrict } from "web3-utils";
import Web3EthAbi from "web3-eth-abi";
import EvmContractEditor from "./EvmContractEditor";
import EvmSendEditor from "./EvmSendEditor";

const MenuGroups = [{ title: "Request", templates: UserOperationTemplate }];
const ABI: AbiItem = {
Expand Down Expand Up @@ -124,12 +124,7 @@ const EvmUserOpEditor = ({
{templateId === "sendTransaction" ? (
<Box my="20px">
<EvmSendEditor
setRequestObject={(params = []) =>
setTransactionToCallData({
method: "eth_sendTransaction",
params,
})
}
setRequestObject={setTransactionToCallData}
account={account}
/>
</Box>
Expand Down

0 comments on commit c634065

Please sign in to comment.