Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feat/evm batch tx editor #80

Merged
merged 3 commits into from
Jan 9, 2024
Merged
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
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");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@mordochi mordochi Dec 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

另外幫我做成 optional 的可以嗎 因為這個 param 其實可以不帶
wallet 理論上還是要用 revert = false 的方式幫處理掉~想讓 QA 也可以測一下 dapp 沒帶的情況 謝謝!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved enhance: optional revert and improve empty tx express

  • 新增 unset 處理沒放 revert 的狀況
  • revert flag default 已經是 true 了, 但因為 Radio value prop 不收 boolean, 因此 revert state 那裡是放字串, 有加 RevertOptionMap 處理最後送進 sdk 的 revert 值

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我是要說 default 放 false lol 講錯了搜哩XDD
貼的那個 spec 就是寫 default false

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