From 933bdb59680ed380db1cd313e2422204aca1dff6 Mon Sep 17 00:00:00 2001 From: Valtteri Karesto Date: Wed, 25 May 2022 13:05:04 +0300 Subject: [PATCH] Add fee estimate button to fee and update the deploying --- components/SetHookDialog.tsx | 487 +++++++++++++++++++++-------------- state/actions/deployHook.tsx | 41 +-- 2 files changed, 313 insertions(+), 215 deletions(-) diff --git a/components/SetHookDialog.tsx b/components/SetHookDialog.tsx index 35d8ef9..0d62c60 100644 --- a/components/SetHookDialog.tsx +++ b/components/SetHookDialog.tsx @@ -21,11 +21,11 @@ import { import { TTS, tts } from "../utils/hookOnCalculator"; import { deployHook } from "../state/actions"; -import type { IAccount } from "../state"; import { useSnapshot } from "valtio"; import state from "../state"; 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) => ({ label: key, @@ -37,6 +37,7 @@ export type SetHookData = { value: keyof TTS; label: string; }[]; + Fee: string; HookNamespace: string; HookParameters: { HookParameter: { @@ -52,176 +53,263 @@ export type SetHookData = { // }[]; }; -export const SetHookDialog: React.FC<{ account: IAccount }> = ({ account }) => { - const snap = useSnapshot(state); - const [isSetHookDialogOpen, setIsSetHookDialogOpen] = useState(false); - const { - register, - handleSubmit, - control, - watch, - setValue, - formState: { errors }, - } = useForm({ - defaultValues: { - HookNamespace: snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || "", - }, - }); - const { fields, append, remove } = useFieldArray({ - control, - name: "HookParameters", // unique name for your Field Array - }); +export const SetHookDialog: React.FC<{ accountIndex: number }> = React.memo( + ({ accountIndex }) => { + const snap = useSnapshot(state); + const account = snap.accounts[accountIndex]; + const [isSetHookDialogOpen, setIsSetHookDialogOpen] = useState(false); + const { + register, + handleSubmit, + control, + watch, + setValue, + getValues, + formState: { errors }, + } = useForm({ + defaultValues: { + HookNamespace: + snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || "", + Invoke: transactionOptions.filter((to) => to.label === "ttPAYMENT"), + }, + }); + const { fields, append, remove } = useFieldArray({ + control, + name: "HookParameters", // unique name for your Field Array + }); + const [formInitialized, setFormInitialized] = useState(false); + const [estimateLoading, setEstimateLoading] = useState(false); - // Update value if activeWat changes - useEffect(() => { - setValue( - "HookNamespace", - snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || "" - ); - }, [snap.activeWat, snap.files, setValue]); - // const { - // fields: grantFields, - // append: grantAppend, - // remove: grantRemove, - // } = useFieldArray({ - // control, - // name: "HookGrants", // unique name for your Field Array - // }); - const [hashedNamespace, setHashedNamespace] = useState(""); - const namespace = watch( - "HookNamespace", - snap.files?.[snap.active]?.name?.split(".")?.[0] || "" - ); - const calculateHashedValue = useCallback(async () => { - const hashedVal = await sha256(namespace); - setHashedNamespace(hashedVal.toUpperCase()); - }, [namespace]); - useEffect(() => { - calculateHashedValue(); - }, [namespace, calculateHashedValue]); - - if (!account) { - return null; - } - - const onSubmit: SubmitHandler = async (data) => { - const currAccount = state.accounts.find( - (acc) => acc.address === account.address - ); - if (currAccount) currAccount.isLoading = true; - const res = await deployHook(account, data); - if (currAccount) currAccount.isLoading = false; - - if (res && res.engine_result === "tesSUCCESS") { - toast.success("Transaction succeeded!"); - return setIsSetHookDialogOpen(false); - } - toast.error(`Transaction failed! (${res?.engine_result_message})`); - }; - - return ( - - - - - -
- Deploy configuration - - - - - to.label === "ttPAYMENT" - )} - render={({ field }) => ( - - {errors.HookNamespace?.type === "required" && ( - - Namespace is required - - )} - - - + const res = await estimateFee(tx, account); + if (res && res.base_fee) { + setValue("Fee", res.base_fee); + } + })(); + } + }, [formInitialized]); + // const { + // fields: grantFields, + // append: grantAppend, + // remove: grantRemove, + // } = useFieldArray({ + // control, + // name: "HookGrants", // unique name for your Field Array + // }); + const [hashedNamespace, setHashedNamespace] = useState(""); + const namespace = watch( + "HookNamespace", + snap.files?.[snap.active]?.name?.split(".")?.[0] || "" + ); + const calculateHashedValue = useCallback(async () => { + const hashedVal = await sha256(namespace); + setHashedNamespace(hashedVal.toUpperCase()); + }, [namespace]); + useEffect(() => { + calculateHashedValue(); + }, [namespace, calculateHashedValue]); + + if (!account) { + return null; + } + + const onSubmit: SubmitHandler = async (data) => { + const currAccount = state.accounts.find( + (acc) => acc.address === account.address + ); + if (currAccount) currAccount.isLoading = true; + const res = await deployHook(account, data); + if (currAccount) currAccount.isLoading = false; + + if (res && res.engine_result === "tesSUCCESS") { + toast.success("Transaction succeeded!"); + return setIsSetHookDialogOpen(false); + } + toast.error(`Transaction failed! (${res?.engine_result_message})`); + }; + return ( + + + + + + + Deploy configuration + + + + + to.label === "ttPAYMENT" + )} + render={({ field }) => ( + - - - - ))} - - - - {/* + /> + {errors.HookNamespace?.type === "required" && ( + + Namespace is required + + )} + + + + + + + + + + {fields.map((field, index) => ( + + + + + + ))} + + + + + + + + + + {errors.Fee?.type === "required" && ( + + Fee is required + + )} + + {/* @@ -269,38 +357,39 @@ export const SetHookDialog: React.FC<{ account: IAccount }> = ({ account }) => { */} - - + + - - - - - {/* */} - - {/* */} - - - - - - -
-
-
- ); -}; + + + + {/* */} + + {/* */} + + + + + + + + + + ); + } +); export default SetHookDialog; diff --git a/state/actions/deployHook.tsx b/state/actions/deployHook.tsx index 628de6e..c5d2afe 100644 --- a/state/actions/deployHook.tsx +++ b/state/actions/deployHook.tsx @@ -50,11 +50,7 @@ function arrayBufferToHex(arrayBuffer?: ArrayBuffer | null) { return result; } -/* deployHook function turns the wasm binary into - * hex string, signs the transaction and deploys it to - * Hooks testnet. - */ -export const deployHook = async ( +export const prepareDeployHookTx = async ( account: IAccount & { name?: string }, data: SetHookData ) => { @@ -93,13 +89,12 @@ export const deployHook = async ( // } // } // }); - if (typeof window !== "undefined") { const tx = { Account: account.address, TransactionType: "SetHook", Sequence: account.sequence, - Fee: "100000", + Fee: data.Fee, Hooks: [ { 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 currentAccount = state.accounts.find( (acc) => acc.address === account.address @@ -137,7 +145,7 @@ export const deployHook = async ( let submitRes; try { - submitRes = await state.client.send({ + submitRes = await state.client?.send({ command: "submit", tx_blob: signedTransaction, }); @@ -216,7 +224,8 @@ export const deleteHook = async (account: IAccount & { name?: string }) => { const keypair = derive.familySeed(account.secret); try { // 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) { // use default value what you defined earlier console.log(err);