Add fee estimate button to fee and update the deploying
This commit is contained in:
@@ -21,11 +21,11 @@ import {
|
|||||||
|
|
||||||
import { TTS, tts } from "../utils/hookOnCalculator";
|
import { TTS, tts } from "../utils/hookOnCalculator";
|
||||||
import { deployHook } from "../state/actions";
|
import { deployHook } from "../state/actions";
|
||||||
import type { IAccount } from "../state";
|
|
||||||
import { useSnapshot } from "valtio";
|
import { useSnapshot } from "valtio";
|
||||||
import state from "../state";
|
import state from "../state";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { sha256 } from "../state/actions/deployHook";
|
import { prepareDeployHookTx, sha256 } from "../state/actions/deployHook";
|
||||||
|
import estimateFee from "../utils/estimateFee";
|
||||||
|
|
||||||
const transactionOptions = Object.keys(tts).map((key) => ({
|
const transactionOptions = Object.keys(tts).map((key) => ({
|
||||||
label: key,
|
label: key,
|
||||||
@@ -37,6 +37,7 @@ export type SetHookData = {
|
|||||||
value: keyof TTS;
|
value: keyof TTS;
|
||||||
label: string;
|
label: string;
|
||||||
}[];
|
}[];
|
||||||
|
Fee: string;
|
||||||
HookNamespace: string;
|
HookNamespace: string;
|
||||||
HookParameters: {
|
HookParameters: {
|
||||||
HookParameter: {
|
HookParameter: {
|
||||||
@@ -52,8 +53,10 @@ export type SetHookData = {
|
|||||||
// }[];
|
// }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SetHookDialog: React.FC<{ account: IAccount }> = ({ account }) => {
|
export const SetHookDialog: React.FC<{ accountIndex: number }> = React.memo(
|
||||||
|
({ accountIndex }) => {
|
||||||
const snap = useSnapshot(state);
|
const snap = useSnapshot(state);
|
||||||
|
const account = snap.accounts[accountIndex];
|
||||||
const [isSetHookDialogOpen, setIsSetHookDialogOpen] = useState(false);
|
const [isSetHookDialogOpen, setIsSetHookDialogOpen] = useState(false);
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
@@ -61,16 +64,21 @@ export const SetHookDialog: React.FC<{ account: IAccount }> = ({ account }) => {
|
|||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
setValue,
|
setValue,
|
||||||
|
getValues,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm<SetHookData>({
|
} = useForm<SetHookData>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
HookNamespace: snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || "",
|
HookNamespace:
|
||||||
|
snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || "",
|
||||||
|
Invoke: transactionOptions.filter((to) => to.label === "ttPAYMENT"),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: "HookParameters", // unique name for your Field Array
|
name: "HookParameters", // unique name for your Field Array
|
||||||
});
|
});
|
||||||
|
const [formInitialized, setFormInitialized] = useState(false);
|
||||||
|
const [estimateLoading, setEstimateLoading] = useState(false);
|
||||||
|
|
||||||
// Update value if activeWat changes
|
// Update value if activeWat changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -78,7 +86,24 @@ export const SetHookDialog: React.FC<{ account: IAccount }> = ({ account }) => {
|
|||||||
"HookNamespace",
|
"HookNamespace",
|
||||||
snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || ""
|
snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || ""
|
||||||
);
|
);
|
||||||
|
setFormInitialized(true);
|
||||||
}, [snap.activeWat, snap.files, setValue]);
|
}, [snap.activeWat, snap.files, setValue]);
|
||||||
|
// Calcucate initial fee estimate when modal opens
|
||||||
|
useEffect(() => {
|
||||||
|
if (formInitialized) {
|
||||||
|
(async () => {
|
||||||
|
const formValues = getValues();
|
||||||
|
const tx = await prepareDeployHookTx(account, formValues);
|
||||||
|
if (!tx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await estimateFee(tx, account);
|
||||||
|
if (res && res.base_fee) {
|
||||||
|
setValue("Fee", res.base_fee);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}, [formInitialized]);
|
||||||
// const {
|
// const {
|
||||||
// fields: grantFields,
|
// fields: grantFields,
|
||||||
// append: grantAppend,
|
// append: grantAppend,
|
||||||
@@ -118,7 +143,6 @@ export const SetHookDialog: React.FC<{ account: IAccount }> = ({ account }) => {
|
|||||||
}
|
}
|
||||||
toast.error(`Transaction failed! (${res?.engine_result_message})`);
|
toast.error(`Transaction failed! (${res?.engine_result_message})`);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={isSetHookDialogOpen} onOpenChange={setIsSetHookDialogOpen}>
|
<Dialog open={isSetHookDialogOpen} onOpenChange={setIsSetHookDialogOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
@@ -178,6 +202,7 @@ export const SetHookDialog: React.FC<{ account: IAccount }> = ({ account }) => {
|
|||||||
<Input readOnly value={hashedNamespace} />
|
<Input readOnly value={hashedNamespace} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box css={{ width: "100%" }}>
|
<Box css={{ width: "100%" }}>
|
||||||
<Label style={{ marginBottom: "10px", display: "block" }}>
|
<Label style={{ marginBottom: "10px", display: "block" }}>
|
||||||
Hook parameters
|
Hook parameters
|
||||||
@@ -221,6 +246,69 @@ export const SetHookDialog: React.FC<{ account: IAccount }> = ({ account }) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box css={{ width: "100%", position: "relative" }}>
|
||||||
|
<Label>Fee</Label>
|
||||||
|
<Box css={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
{...register("Fee", { required: true })}
|
||||||
|
autoComplete={"off"}
|
||||||
|
defaultValue={10000}
|
||||||
|
css={{
|
||||||
|
"-moz-appearance": "textfield",
|
||||||
|
"&::-webkit-outer-spin-button": {
|
||||||
|
"-webkit-appearance": "none",
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
"&::-webkit-inner-spin-button ": {
|
||||||
|
"-webkit-appearance": "none",
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant="primary"
|
||||||
|
outline
|
||||||
|
isLoading={estimateLoading}
|
||||||
|
css={{
|
||||||
|
position: "absolute",
|
||||||
|
right: "$2",
|
||||||
|
fontSize: "$xs",
|
||||||
|
cursor: "pointer",
|
||||||
|
alignContent: "center",
|
||||||
|
display: "flex",
|
||||||
|
}}
|
||||||
|
onClick={async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setEstimateLoading(true);
|
||||||
|
const formValues = getValues();
|
||||||
|
try {
|
||||||
|
const tx = await prepareDeployHookTx(
|
||||||
|
account,
|
||||||
|
formValues
|
||||||
|
);
|
||||||
|
if (tx) {
|
||||||
|
const res = await estimateFee(tx, account);
|
||||||
|
|
||||||
|
if (res && res.base_fee) {
|
||||||
|
setValue("Fee", res.base_fee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {}
|
||||||
|
|
||||||
|
setEstimateLoading(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Suggest
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
{errors.Fee?.type === "required" && (
|
||||||
|
<Box css={{ display: "inline", color: "$red11" }}>
|
||||||
|
Fee is required
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
{/* <Box css={{ width: "100%" }}>
|
{/* <Box css={{ width: "100%" }}>
|
||||||
<label style={{ marginBottom: "10px", display: "block" }}>
|
<label style={{ marginBottom: "10px", display: "block" }}>
|
||||||
Hook Grants
|
Hook Grants
|
||||||
@@ -301,6 +389,7 @@ export const SetHookDialog: React.FC<{ account: IAccount }> = ({ account }) => {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export default SetHookDialog;
|
export default SetHookDialog;
|
||||||
|
|||||||
@@ -50,11 +50,7 @@ function arrayBufferToHex(arrayBuffer?: ArrayBuffer | null) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* deployHook function turns the wasm binary into
|
export const prepareDeployHookTx = async (
|
||||||
* hex string, signs the transaction and deploys it to
|
|
||||||
* Hooks testnet.
|
|
||||||
*/
|
|
||||||
export const deployHook = async (
|
|
||||||
account: IAccount & { name?: string },
|
account: IAccount & { name?: string },
|
||||||
data: SetHookData
|
data: SetHookData
|
||||||
) => {
|
) => {
|
||||||
@@ -93,13 +89,12 @@ export const deployHook = async (
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
|
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
const tx = {
|
const tx = {
|
||||||
Account: account.address,
|
Account: account.address,
|
||||||
TransactionType: "SetHook",
|
TransactionType: "SetHook",
|
||||||
Sequence: account.sequence,
|
Sequence: account.sequence,
|
||||||
Fee: "100000",
|
Fee: data.Fee,
|
||||||
Hooks: [
|
Hooks: [
|
||||||
{
|
{
|
||||||
Hook: {
|
Hook: {
|
||||||
@@ -118,15 +113,28 @@ export const deployHook = async (
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
return tx;
|
||||||
const keypair = derive.familySeed(account.secret);
|
|
||||||
try {
|
|
||||||
// Update tx Fee value with network estimation
|
|
||||||
await estimateFee(tx, keypair);
|
|
||||||
} catch (err) {
|
|
||||||
// use default value what you defined earlier
|
|
||||||
console.log(err);
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* deployHook function turns the wasm binary into
|
||||||
|
* hex string, signs the transaction and deploys it to
|
||||||
|
* Hooks testnet.
|
||||||
|
*/
|
||||||
|
export const deployHook = async (
|
||||||
|
account: IAccount & { name?: string },
|
||||||
|
data: SetHookData
|
||||||
|
) => {
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
const tx = await prepareDeployHookTx(account, data);
|
||||||
|
if (!tx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!state.client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const keypair = derive.familySeed(account.secret);
|
||||||
|
|
||||||
const { signedTransaction } = sign(tx, keypair);
|
const { signedTransaction } = sign(tx, keypair);
|
||||||
const currentAccount = state.accounts.find(
|
const currentAccount = state.accounts.find(
|
||||||
(acc) => acc.address === account.address
|
(acc) => acc.address === account.address
|
||||||
@@ -137,7 +145,7 @@ export const deployHook = async (
|
|||||||
let submitRes;
|
let submitRes;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
submitRes = await state.client.send({
|
submitRes = await state.client?.send({
|
||||||
command: "submit",
|
command: "submit",
|
||||||
tx_blob: signedTransaction,
|
tx_blob: signedTransaction,
|
||||||
});
|
});
|
||||||
@@ -216,7 +224,8 @@ export const deleteHook = async (account: IAccount & { name?: string }) => {
|
|||||||
const keypair = derive.familySeed(account.secret);
|
const keypair = derive.familySeed(account.secret);
|
||||||
try {
|
try {
|
||||||
// Update tx Fee value with network estimation
|
// Update tx Fee value with network estimation
|
||||||
await estimateFee(tx, keypair);
|
const res = await estimateFee(tx, account);
|
||||||
|
tx["Fee"] = res?.base_fee ? res?.base_fee : "1000";
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// use default value what you defined earlier
|
// use default value what you defined earlier
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
|||||||
Reference in New Issue
Block a user