Revert "Linkify engine error codes and some refactor."

This reverts commit 5505f0ac87.
This commit is contained in:
muzam1l
2022-08-09 01:55:42 +05:30
parent 5505f0ac87
commit 2086291d4d
7 changed files with 156 additions and 207 deletions

View File

@@ -5,7 +5,6 @@ import { subscribeKey } from "valtio/utils";
import { Select } from ".";
import state, { ILog, transactionsState } from "../state";
import { extractJSON } from "../utils/json";
import EnrichAccounts from "./EnrichAccounts";
import LogBox from "./LogBox";
interface ISelect<T = string> {
@@ -100,17 +99,12 @@ const addListeners = (account: ISelect | null) => {
subscribeKey(streamState, "selectedAccount", addListeners);
const clearLog = () => {
streamState.logs = [];
streamState.statusChangeTimestamp = Date.now();
};
const DebugStream = () => {
const { selectedAccount, logs } = useSnapshot(streamState);
const { activeHeader: activeTxTab } = useSnapshot(transactionsState);
const { accounts } = useSnapshot(state);
const accountOptions = accounts.map(acc => ({
const accountOptions = accounts.map((acc) => ({
label: acc.name,
value: acc.address,
}));
@@ -123,7 +117,7 @@ const DebugStream = () => {
options={accountOptions}
hideSelectedOptions
value={selectedAccount}
onChange={acc => {
onChange={(acc) => {
streamState.socket?.close(
4999,
"Old connection closed because user switched account"
@@ -137,13 +131,18 @@ const DebugStream = () => {
useEffect(() => {
const account = transactionsState.transactions.find(
tx => tx.header === activeTxTab
(tx) => tx.header === activeTxTab
)?.state.selectedAccount;
if (account && account.value !== streamState.selectedAccount?.value)
streamState.selectedAccount = account;
}, [activeTxTab]);
const clearLog = () => {
streamState.logs = [];
streamState.statusChangeTimestamp = Date.now();
};
return (
<LogBox
enhanced
@@ -171,17 +170,13 @@ export const pushLog = (
const timestring = !timestamp ? tm : new Date(timestamp).toLocaleTimeString();
const extracted = extractJSON(msg);
const _message = !extracted
const message = !extracted
? msg
: msg.slice(0, extracted.start) + msg.slice(extracted.end + 1);
const message = ref(<EnrichAccounts str={_message} />);
const _jsonData = extracted
const jsonData = extracted
? JSON.stringify(extracted.result, null, 2)
: undefined;
const jsonData = _jsonData
? ref(<EnrichAccounts str={_jsonData} />)
: undefined;
if (extracted?.result?.id?._Request?.includes("hooks-builder-req")) {
return;

View File

@@ -1,48 +0,0 @@
import { FC, useState } from "react";
import regexifyString from "regexify-string";
import { useSnapshot } from "valtio";
import { Link } from ".";
import state from "../state";
import { AccountDialog } from "./Accounts";
interface EnrichAccountsProps {
str?: string;
}
const EnrichAccounts: FC<EnrichAccountsProps> = ({ str }) => {
const { accounts } = useSnapshot(state);
const [dialogAccount, setDialogAccount] = useState<string | null>(null);
if (!str || !accounts.length) return <>{str}</>;
const pattern = `(${accounts.map(acc => acc.address).join("|")})`;
const res = regexifyString({
pattern: new RegExp(pattern, "gim"),
decorator: (match, idx) => {
const name = accounts.find(acc => acc.address === match)?.name;
return (
<Link
key={match + idx}
as="a"
onClick={() => setDialogAccount(match)}
title={match}
highlighted
>
{name || match}
</Link>
);
},
input: str,
});
return (
<>
{res}
<AccountDialog
setActiveAccountAddress={setDialogAccount}
activeAccountAddress={dialogAccount}
/>
</>
);
};
export default EnrichAccounts;

View File

@@ -1,12 +1,22 @@
import { useRef, useLayoutEffect, ReactNode, FC, useState } from "react";
import {
useRef,
useLayoutEffect,
ReactNode,
FC,
useState,
useCallback,
} from "react";
import { IconProps, Notepad, Prohibit } from "phosphor-react";
import useStayScrolled from "react-stay-scrolled";
import NextLink from "next/link";
import Container from "./Container";
import LogText from "./LogText";
import { ILog } from "../state";
import state, { ILog } from "../state";
import { Pre, Link, Heading, Button, Text, Flex, Box } from ".";
import regexifyString from "regexify-string";
import { useSnapshot } from "valtio";
import { AccountDialog } from "./Accounts";
interface ILogBox {
title: string;
@@ -140,24 +150,70 @@ const LogBox: FC<ILogBox> = ({
export const Log: FC<ILog> = ({
type,
timestring,
message,
message: _message,
link,
linkText,
defaultCollapsed,
jsonData,
jsonData: _jsonData,
}) => {
const [expanded, setExpanded] = useState(!defaultCollapsed);
const { accounts } = useSnapshot(state);
const [dialogAccount, setDialogAccount] = useState<string | null>(null);
const enrichAccounts = useCallback(
(str?: string): ReactNode => {
if (!str || !accounts.length) return str;
const pattern = `(${accounts.map(acc => acc.address).join("|")})`;
const res = regexifyString({
pattern: new RegExp(pattern, "gim"),
decorator: (match, idx) => {
const name = accounts.find(acc => acc.address === match)?.name;
return (
<Link
key={match + idx}
as="a"
onClick={() => setDialogAccount(match)}
title={match}
highlighted
>
{name || match}
</Link>
);
},
input: str,
});
return <>{res}</>;
},
[accounts]
);
let message: ReactNode;
if (typeof _message === "string") {
_message = _message.trim().replace(/\n /gi, "\n");
if (_message) message = enrichAccounts(_message);
else message = <Text muted>{'""'}</Text>
} else {
message = _message;
}
const jsonData = enrichAccounts(_jsonData);
if (!message) message = <Text muted>{'""'}</Text>;
return (
<>
<AccountDialog
setActiveAccountAddress={setDialogAccount}
activeAccountAddress={dialogAccount}
/>
<LogText variant={type}>
{timestring && (
<Text muted monospace>
{timestring}{" "}
</Text>
)}
<Pre>{message}</Pre>
<Pre>{message} </Pre>
{link && (
<NextLink href={link} shallow passHref>
<Link as="a">{linkText}</Link>

View File

@@ -1,23 +0,0 @@
import { FC } from "react";
import { Link } from ".";
interface Props {
result?: string;
}
const ResultLink: FC<Props> = ({ result }) => {
if (!result) return null;
return (
<Link
as="a"
title={result}
href={"https://xrpl.org/transaction-results.html"}
target="_blank"
rel="noopener noreferrer"
>
{result}
</Link>
);
};
export default ResultLink;

View File

@@ -6,15 +6,14 @@ import calculateHookOn, { TTS } from "../../utils/hookOnCalculator";
import { Link } from "../../components";
import { ref } from "valtio";
import estimateFee from "../../utils/estimateFee";
import { SetHookData } from "../../utils/setHook";
import ResultLink from "../../components/ResultLink";
import { SetHookData } from '../../utils/setHook';
export const sha256 = async (string: string) => {
const utf8 = new TextEncoder().encode(string);
const hashBuffer = await crypto.subtle.digest("SHA-256", utf8);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray
.map(bytes => bytes.toString(16).padStart(2, "0"))
.map((bytes) => bytes.toString(16).padStart(2, "0"))
.join("");
return hashHex;
};
@@ -57,7 +56,7 @@ export const prepareDeployHookTx = async (
) => {
const activeFile = state.files[state.active]?.compiledContent
? state.files[state.active]
: state.files.filter(file => file.compiledContent)[0];
: state.files.filter((file) => file.compiledContent)[0];
if (!state.files || state.files.length === 0) {
return;
@@ -70,12 +69,12 @@ export const prepareDeployHookTx = async (
return;
}
const HookNamespace = (await sha256(data.HookNamespace)).toUpperCase();
const hookOnValues: (keyof TTS)[] = data.Invoke.map(tt => tt.value);
const hookOnValues: (keyof TTS)[] = data.Invoke.map((tt) => tt.value);
const { HookParameters } = data;
const filteredHookParameters = HookParameters.filter(
hp =>
(hp) =>
hp.HookParameter.HookParameterName && hp.HookParameter.HookParameterValue
)?.map(aa => ({
)?.map((aa) => ({
HookParameter: {
HookParameterName: toHex(aa.HookParameter.HookParameterName || ""),
HookParameterValue: aa.HookParameter.HookParameterValue || "",
@@ -129,7 +128,7 @@ export const deployHook = async (
if (typeof window !== "undefined") {
const activeFile = state.files[state.active]?.compiledContent
? state.files[state.active]
: state.files.filter(file => file.compiledContent)[0];
: state.files.filter((file) => file.compiledContent)[0];
state.deployValues[activeFile.name] = data;
const tx = await prepareDeployHookTx(account, data);
if (!tx) {
@@ -142,7 +141,7 @@ export const deployHook = async (
const { signedTransaction } = sign(tx, keypair);
const currentAccount = state.accounts.find(
acc => acc.address === account.address
(acc) => acc.address === account.address
);
if (currentAccount) {
currentAccount.isLoading = true;
@@ -155,26 +154,6 @@ export const deployHook = async (
tx_blob: signedTransaction,
});
const txHash = submitRes.tx_json?.hash;
const resultMsg = ref(
<>
[<ResultLink result={submitRes.engine_result} />]{" "}
{submitRes.engine_result_message}{" "}
{txHash && (
<>
Transaction hash:{" "}
<Link
as="a"
href={`https://${process.env.NEXT_PUBLIC_EXPLORER_URL}/${txHash}`}
target="_blank"
rel="noopener noreferrer"
>
{txHash}
</Link>
</>
)}
</>
);
if (submitRes.engine_result === "tesSUCCESS") {
state.deployLogs.push({
type: "success",
@@ -182,17 +161,28 @@ export const deployHook = async (
});
state.deployLogs.push({
type: "success",
message: resultMsg,
});
} else if (submitRes.engine_result) {
state.deployLogs.push({
type: "error",
message: resultMsg,
message: ref(
<>
[{submitRes.engine_result}] {submitRes.engine_result_message}{" "}
Transaction hash:{" "}
<Link
as="a"
href={`https://${process.env.NEXT_PUBLIC_EXPLORER_URL}/${submitRes.tx_json?.hash}`}
target="_blank"
rel="noopener noreferrer"
>
{submitRes.tx_json?.hash}
</Link>
</>
),
// message: `[${submitRes.engine_result}] ${submitRes.engine_result_message} Validated ledger index: ${submitRes.validated_ledger_index}`,
});
} else {
state.deployLogs.push({
type: "error",
message: `[${submitRes.error}] ${submitRes.error_exception}`,
message: `[${submitRes.engine_result || submitRes.error}] ${
submitRes.engine_result_message || submitRes.error_exception
}`,
});
}
} catch (err) {
@@ -214,7 +204,7 @@ export const deleteHook = async (account: IAccount & { name?: string }) => {
return;
}
const currentAccount = state.accounts.find(
acc => acc.address === account.address
(acc) => acc.address === account.address
);
if (currentAccount?.isLoading || !currentAccount?.hooks.length) {
return;

View File

@@ -0,0 +1,57 @@
import { derive, sign } from "xrpl-accountlib";
import state from '..'
import type { IAccount } from "..";
interface TransactionOptions {
TransactionType: string,
Account?: string,
Fee?: string,
Destination?: string
[index: string]: any
}
interface OtherOptions {
logPrefix?: string
}
export const sendTransaction = async (account: IAccount, txOptions: TransactionOptions, options?: OtherOptions) => {
if (!state.client) throw Error('XRPL client not initalized')
const { Fee = "1000", ...opts } = txOptions
const tx: TransactionOptions = {
Account: account.address,
Sequence: account.sequence,
Fee, // TODO auto-fillable default
...opts
};
const { logPrefix = '' } = options || {}
try {
const signedAccount = derive.familySeed(account.secret);
const { signedTransaction } = sign(tx, signedAccount);
const response = await state.client.send({
command: "submit",
tx_blob: signedTransaction,
});
if (response.engine_result === "tesSUCCESS") {
state.transactionLogs.push({
type: 'success',
message: `${logPrefix}[${response.engine_result}] ${response.engine_result_message}`
})
} else {
state.transactionLogs.push({
type: "error",
message: `${logPrefix}[${response.error || response.engine_result}] ${response.error_exception || response.engine_result_message}`,
});
}
const currAcc = state.accounts.find(acc => acc.address === account.address);
if (currAcc && response.account_sequence_next) {
currAcc.sequence = response.account_sequence_next;
}
} catch (err) {
console.error(err);
state.transactionLogs.push({
type: "error",
message: err instanceof Error ? `${logPrefix}Error: ${err.message}` : `${logPrefix}Something went wrong, try again later`,
});
}
};

View File

@@ -1,78 +0,0 @@
import { derive, sign } from "xrpl-accountlib";
import state from "..";
import type { IAccount } from "..";
import ResultLink from "../../components/ResultLink";
import { ref } from "valtio";
interface TransactionOptions {
TransactionType: string;
Account?: string;
Fee?: string;
Destination?: string;
[index: string]: any;
}
interface OtherOptions {
logPrefix?: string;
}
export const sendTransaction = async (
account: IAccount,
txOptions: TransactionOptions,
options?: OtherOptions
) => {
if (!state.client) throw Error("XRPL client not initalized");
const { Fee = "1000", ...opts } = txOptions;
const tx: TransactionOptions = {
Account: account.address,
Sequence: account.sequence,
Fee, // TODO auto-fillable default
...opts,
};
const { logPrefix = "" } = options || {};
try {
const signedAccount = derive.familySeed(account.secret);
const { signedTransaction } = sign(tx, signedAccount);
const response = await state.client.send({
command: "submit",
tx_blob: signedTransaction,
});
const resultMsg = ref(
<>
{logPrefix}[<ResultLink result={response.engine_result} />]{" "}
{response.engine_result_message}
</>
);
if (response.engine_result === "tesSUCCESS") {
state.transactionLogs.push({
type: "success",
message: resultMsg,
});
} else if (response.engine_result) {
state.transactionLogs.push({
type: "error",
message: resultMsg,
});
} else {
state.transactionLogs.push({
type: "error",
message: `${logPrefix}[${response.error}] ${response.error_exception}`,
});
}
const currAcc = state.accounts.find(acc => acc.address === account.address);
if (currAcc && response.account_sequence_next) {
currAcc.sequence = response.account_sequence_next;
}
} catch (err) {
console.error(err);
state.transactionLogs.push({
type: "error",
message:
err instanceof Error
? `${logPrefix}Error: ${err.message}`
: `${logPrefix}Something went wrong, try again later`,
});
}
};