Add fee estimate button to fee and update the deploying

This commit is contained in:
Valtteri Karesto
2022-05-25 13:05:04 +03:00
parent 864711697b
commit 933bdb5968
2 changed files with 313 additions and 215 deletions

View File

@@ -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;

View File

@@ -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);