Compare commits
17 Commits
fix/renami
...
feat/flags
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f0fc838be | ||
|
|
fa93912c38 | ||
|
|
f5cb76c302 | ||
|
|
df1d65dcab | ||
|
|
1513f78991 | ||
|
|
3a064f307b | ||
|
|
6fca05f310 | ||
|
|
31e67d382f | ||
|
|
27475301e4 | ||
|
|
2d9ca2674e | ||
|
|
221c727af6 | ||
|
|
3b0a8c44c9 | ||
|
|
094f739b80 | ||
|
|
2d82966b3b | ||
|
|
93c5ef231e | ||
|
|
53c2104b94 | ||
|
|
c336ff8334 |
@@ -5,6 +5,7 @@ import { subscribeKey } from 'valtio/utils'
|
||||
import { Select } from '.'
|
||||
import state, { ILog, transactionsState } from '../state'
|
||||
import { extractJSON } from '../utils/json'
|
||||
import EnrichLog from './EnrichLog'
|
||||
import LogBox from './LogBox'
|
||||
|
||||
interface ISelect<T = string> {
|
||||
@@ -99,6 +100,11 @@ 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)
|
||||
@@ -134,11 +140,6 @@ const DebugStream = () => {
|
||||
streamState.selectedAccount = account
|
||||
}, [activeTxTab])
|
||||
|
||||
const clearLog = () => {
|
||||
streamState.logs = []
|
||||
streamState.statusChangeTimestamp = Date.now()
|
||||
}
|
||||
|
||||
return (
|
||||
<LogBox enhanced renderNav={renderNav} title="Debug stream" logs={logs} clearLog={clearLog} />
|
||||
)
|
||||
@@ -157,9 +158,11 @@ export const pushLog = (str: any, opts: Partial<Pick<ILog, 'type'>> = {}): ILog
|
||||
const timestring = !timestamp ? tm : new Date(timestamp).toLocaleTimeString()
|
||||
|
||||
const extracted = extractJSON(msg)
|
||||
const message = !extracted ? msg : msg.slice(0, extracted.start) + msg.slice(extracted.end + 1)
|
||||
const _message = !extracted ? msg : msg.slice(0, extracted.start) + msg.slice(extracted.end + 1)
|
||||
const message = ref(<EnrichLog str={_message} />)
|
||||
|
||||
const jsonData = extracted ? JSON.stringify(extracted.result, null, 2) : undefined
|
||||
const _jsonData = extracted ? JSON.stringify(extracted.result, null, 2) : undefined
|
||||
const jsonData = _jsonData ? ref(<EnrichLog str={_jsonData} />) : undefined
|
||||
|
||||
if (extracted?.result?.id?._Request?.includes('hooks-builder-req')) {
|
||||
return
|
||||
|
||||
73
components/EnrichLog.tsx
Normal file
73
components/EnrichLog.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
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'
|
||||
import Tooltip from './Tooltip'
|
||||
import hookSetCodes from '../content/hook-set-codes.json'
|
||||
import { capitalize } from '../utils/helpers'
|
||||
|
||||
interface EnrichLogProps {
|
||||
str?: string
|
||||
}
|
||||
|
||||
const EnrichLog: FC<EnrichLogProps> = ({ str }) => {
|
||||
const { accounts } = useSnapshot(state)
|
||||
const [dialogAccount, setDialogAccount] = useState<string | null>(null)
|
||||
if (!str || !accounts.length) return <>{str}</>
|
||||
|
||||
const addrs = accounts.map(acc => acc.address)
|
||||
const regex = `(${addrs.join('|')}|HookSet\\(\\d+\\))`
|
||||
const res = regexifyString({
|
||||
pattern: new RegExp(regex, 'gim'),
|
||||
decorator: (match, idx) => {
|
||||
if (match.startsWith('r')) {
|
||||
// Account
|
||||
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>
|
||||
)
|
||||
}
|
||||
if (match.startsWith('HookSet')) {
|
||||
const code = match.match(/^HookSet\((\d+)\)/)?.[1]
|
||||
const val = hookSetCodes.find(v => code && v.code === +code)
|
||||
console.log({ code, val })
|
||||
if (!val) return match
|
||||
|
||||
const content = capitalize(val.description) || 'No hint available!'
|
||||
return (
|
||||
<>
|
||||
HookSet(
|
||||
<Tooltip content={content}>
|
||||
<Link>{val.identifier}</Link>
|
||||
</Tooltip>
|
||||
)
|
||||
</>
|
||||
)
|
||||
}
|
||||
return match
|
||||
},
|
||||
input: str
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
{res}
|
||||
<AccountDialog
|
||||
setActiveAccountAddress={setDialogAccount}
|
||||
activeAccountAddress={dialogAccount}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default EnrichLog
|
||||
@@ -1,15 +1,12 @@
|
||||
import { useRef, useLayoutEffect, ReactNode, FC, useState, useCallback } from 'react'
|
||||
import { useRef, useLayoutEffect, ReactNode, FC, useState } 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 state, { ILog } from '../state'
|
||||
import { 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
|
||||
@@ -143,70 +140,25 @@ 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 === undefined) message = <Text muted>{'undefined'}</Text>
|
||||
else 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>
|
||||
@@ -219,7 +171,6 @@ export const Log: FC<ILog> = ({
|
||||
)}
|
||||
{expanded && jsonData && <Pre block>{jsonData}</Pre>}
|
||||
</LogText>
|
||||
<br />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
24
components/ResultLink.tsx
Normal file
24
components/ResultLink.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { FC } from 'react'
|
||||
import { Link } from '.'
|
||||
|
||||
interface Props {
|
||||
result?: string
|
||||
}
|
||||
|
||||
const ResultLink: FC<Props> = ({ result }) => {
|
||||
if (!result) return null
|
||||
let href: string
|
||||
if (result === 'tesSUCCESS') {
|
||||
href = 'https://xrpl.org/tes-success.html'
|
||||
} else {
|
||||
// Going shortcut here because of url structure, if that changes we will do it manually
|
||||
href = `https://xrpl.org/${result.slice(0, 3)}-codes.html`
|
||||
}
|
||||
return (
|
||||
<Link as="a" href={href} target="_blank" rel="noopener noreferrer">
|
||||
{result}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default ResultLink
|
||||
@@ -72,7 +72,12 @@ const Tooltip: React.FC<React.ComponentProps<typeof StyledContent> & ITooltip> =
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<TooltipPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>
|
||||
<TooltipPrimitive.Root
|
||||
open={open}
|
||||
defaultOpen={defaultOpen}
|
||||
onOpenChange={onOpenChange}
|
||||
delayDuration={100}
|
||||
>
|
||||
<TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>
|
||||
<StyledContent side="bottom" align="center" {...rest}>
|
||||
<div dangerouslySetInnerHTML={{ __html: content }} />
|
||||
|
||||
@@ -19,6 +19,7 @@ import { TxJson } from './json'
|
||||
import { TxUI } from './ui'
|
||||
import { default as _estimateFee } from '../../utils/estimateFee'
|
||||
import toast from 'react-hot-toast'
|
||||
import { combineFlags, extractFlags, transactionFlags } from '../../state/constants/flags'
|
||||
|
||||
export interface TransactionProps {
|
||||
header: string
|
||||
@@ -39,14 +40,17 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
|
||||
|
||||
const prepareOptions = useCallback(
|
||||
(state: Partial<TransactionState> = txState) => {
|
||||
const { selectedTransaction, selectedDestAccount, selectedAccount, txFields } = state
|
||||
const { selectedTransaction, selectedDestAccount, selectedAccount, txFields, selectedFlags } =
|
||||
state
|
||||
|
||||
const TransactionType = selectedTransaction?.value || null
|
||||
const Destination = selectedDestAccount?.value || txFields?.Destination
|
||||
const Account = selectedAccount?.value || null
|
||||
const Flags = combineFlags(selectedFlags?.map(flag => flag.value)) || txFields?.Flags
|
||||
|
||||
return prepareTransaction({
|
||||
...txFields,
|
||||
Flags,
|
||||
TransactionType,
|
||||
Destination,
|
||||
Account
|
||||
@@ -136,8 +140,13 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
|
||||
} else {
|
||||
fields.Destination = undefined
|
||||
}
|
||||
nwState.txFields = fields
|
||||
|
||||
if (transactionType?.value && transactionFlags[transactionType?.value] && fields.Flags) {
|
||||
nwState.selectedFlags = extractFlags(transactionType.value, fields.Flags)
|
||||
fields.Flags = undefined
|
||||
}
|
||||
|
||||
nwState.txFields = fields
|
||||
const state = modifyTxState(header, nwState, { replaceState: true })
|
||||
const editorValue = getJsonString(state)
|
||||
return setState({ editorValue })
|
||||
@@ -179,7 +188,12 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
|
||||
estimateFee={estimateFee}
|
||||
/>
|
||||
) : (
|
||||
<TxUI state={txState} setState={setState} estimateFee={estimateFee} />
|
||||
<TxUI
|
||||
state={txState}
|
||||
resetState={resetState}
|
||||
setState={setState}
|
||||
estimateFee={estimateFee}
|
||||
/>
|
||||
)}
|
||||
<Flex
|
||||
row
|
||||
|
||||
@@ -17,16 +17,19 @@ import state from '../../state'
|
||||
import { streamState } from '../DebugStream'
|
||||
import { Button } from '..'
|
||||
import Textarea from '../Textarea'
|
||||
import { getFlags } from '../../state/constants/flags'
|
||||
|
||||
interface UIProps {
|
||||
setState: (pTx?: Partial<TransactionState> | undefined) => TransactionState | undefined
|
||||
resetState: (tt?: SelectOption) => TransactionState | undefined
|
||||
state: TransactionState
|
||||
estimateFee?: (...arg: any) => Promise<string | undefined>
|
||||
}
|
||||
|
||||
export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) => {
|
||||
export const TxUI: FC<UIProps> = ({ state: txState, setState, resetState, estimateFee }) => {
|
||||
const { accounts } = useSnapshot(state)
|
||||
const { selectedAccount, selectedDestAccount, selectedTransaction, txFields } = txState
|
||||
const { selectedAccount, selectedDestAccount, selectedTransaction, txFields, selectedFlags } =
|
||||
txState
|
||||
|
||||
const accountOptions: SelectOption[] = accounts.map(acc => ({
|
||||
label: acc.name,
|
||||
@@ -40,23 +43,15 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) =>
|
||||
}))
|
||||
.filter(acc => acc.value !== selectedAccount?.value)
|
||||
|
||||
const flagsOptions: SelectOption[] = Object.entries(
|
||||
getFlags(selectedTransaction?.value) || {}
|
||||
).map(([label, value]) => ({
|
||||
label,
|
||||
value
|
||||
}))
|
||||
|
||||
const [feeLoading, setFeeLoading] = useState(false)
|
||||
|
||||
const resetFields = useCallback(
|
||||
(tt: string) => {
|
||||
const fields = getTxFields(tt)
|
||||
|
||||
if (fields.Destination !== undefined) {
|
||||
setState({ selectedDestAccount: null })
|
||||
fields.Destination = ''
|
||||
} else {
|
||||
fields.Destination = undefined
|
||||
}
|
||||
return setState({ txFields: fields })
|
||||
},
|
||||
[setState]
|
||||
)
|
||||
|
||||
const handleSetAccount = (acc: SelectOption) => {
|
||||
setState({ selectedAccount: acc })
|
||||
streamState.selectedAccount = acc
|
||||
@@ -92,11 +87,11 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) =>
|
||||
(tt: SelectOption) => {
|
||||
setState({ selectedTransaction: tt })
|
||||
|
||||
const newState = resetFields(tt.value)
|
||||
const newState = resetState(tt)
|
||||
|
||||
handleEstimateFee(newState, true)
|
||||
},
|
||||
[handleEstimateFee, resetFields, setState]
|
||||
[handleEstimateFee, resetState, setState]
|
||||
)
|
||||
|
||||
const switchToJson = () => setState({ viewType: 'json' })
|
||||
@@ -115,14 +110,16 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) =>
|
||||
[selectedTransaction?.value]
|
||||
)
|
||||
|
||||
const specialFields = ['TransactionType', 'Account']
|
||||
const richFields = ['TransactionType', 'Account']
|
||||
if (fields.Destination !== undefined) {
|
||||
specialFields.push('Destination')
|
||||
richFields.push('Destination')
|
||||
}
|
||||
|
||||
const otherFields = Object.keys(txFields).filter(k => !specialFields.includes(k)) as [
|
||||
keyof TxFields
|
||||
]
|
||||
if (flagsOptions.length) {
|
||||
richFields.push('Flags')
|
||||
}
|
||||
|
||||
const otherFields = Object.keys(txFields).filter(k => !richFields.includes(k)) as [keyof TxFields]
|
||||
|
||||
return (
|
||||
<Container
|
||||
@@ -179,7 +176,32 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) =>
|
||||
onChange={(acc: any) => handleSetAccount(acc)} // TODO make react-select have correct types for acc
|
||||
/>
|
||||
</Flex>
|
||||
{fields.Destination !== undefined && (
|
||||
{richFields.includes('Destination') && (
|
||||
<Flex
|
||||
row
|
||||
fluid
|
||||
css={{
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
mb: '$3',
|
||||
pr: '1px'
|
||||
}}
|
||||
>
|
||||
<Text muted css={{ mr: '$3', textAlign: 'end' }}>
|
||||
Destination account:{' '}
|
||||
</Text>
|
||||
<Select
|
||||
instanceId="to-account"
|
||||
placeholder="Select the destination account"
|
||||
css={{ width: '70%' }}
|
||||
options={destAccountOptions}
|
||||
value={selectedDestAccount}
|
||||
isClearable
|
||||
onChange={(acc: any) => setState({ selectedDestAccount: acc })}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
{richFields.includes('Flags') && (
|
||||
<Flex
|
||||
row
|
||||
fluid
|
||||
@@ -191,16 +213,21 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) =>
|
||||
}}
|
||||
>
|
||||
<Text muted css={{ mr: '$3' }}>
|
||||
Destination account:{' '}
|
||||
Flags:{' '}
|
||||
</Text>
|
||||
<Select
|
||||
instanceId="to-account"
|
||||
placeholder="Select the destination account"
|
||||
css={{ width: '70%' }}
|
||||
options={destAccountOptions}
|
||||
value={selectedDestAccount}
|
||||
isClearable
|
||||
onChange={(acc: any) => setState({ selectedDestAccount: acc })}
|
||||
css={{ width: '70%' }}
|
||||
instanceId="flags"
|
||||
placeholder="Select flags to apply"
|
||||
menuPosition="fixed"
|
||||
value={selectedFlags}
|
||||
isMulti
|
||||
options={flagsOptions}
|
||||
onChange={flags => setState({ selectedFlags: flags as any })}
|
||||
closeMenuOnSelect={
|
||||
selectedFlags ? selectedFlags.length >= flagsOptions.length - 1 : false
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
409
content/hook-set-codes.json
Normal file
409
content/hook-set-codes.json
Normal file
@@ -0,0 +1,409 @@
|
||||
[
|
||||
{
|
||||
"code": 1,
|
||||
"identifier": "AMENDMENT_DISABLED",
|
||||
"description": "attempt to HookSet when amendment is not yet enabled."
|
||||
},
|
||||
{
|
||||
"code": 2,
|
||||
"identifier": "API_ILLEGAL",
|
||||
"description": "HookSet object contained HookApiVersion for existing HookDefinition"
|
||||
},
|
||||
{
|
||||
"code": 3,
|
||||
"identifier": "API_INVALID",
|
||||
"description": "HookSet object contained HookApiVersion for unrecognised hook API "
|
||||
},
|
||||
{
|
||||
"code": 4,
|
||||
"identifier": "API_MISSING",
|
||||
"description": "HookSet object lacked HookApiVersion"
|
||||
},
|
||||
{
|
||||
"code": 5,
|
||||
"identifier": "BLOCK_ILLEGAL",
|
||||
"description": " a block end instruction moves execution below depth 0 {{}}`}` <= like this"
|
||||
},
|
||||
{
|
||||
"code": 6,
|
||||
"identifier": "CALL_ILLEGAL",
|
||||
"description": "wasm tries to call a non-whitelisted function"
|
||||
},
|
||||
{
|
||||
"code": 7,
|
||||
"identifier": "CALL_INDIRECT",
|
||||
"description": "wasm used call indirect instruction which is disallowed"
|
||||
},
|
||||
{
|
||||
"code": 8,
|
||||
"identifier": "CREATE_FLAG",
|
||||
"description": "create operation requires hsoOVERRIDE"
|
||||
},
|
||||
{
|
||||
"code": 9,
|
||||
"identifier": "DELETE_FIELD",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"code": 10,
|
||||
"identifier": "DELETE_FLAG",
|
||||
"description": "delete operation requires hsoOVERRIDE"
|
||||
},
|
||||
{
|
||||
"code": 11,
|
||||
"identifier": "DELETE_NOTHING",
|
||||
"description": "delete operation would delete nothing"
|
||||
},
|
||||
{
|
||||
"code": 12,
|
||||
"identifier": "EXPORTS_MISSING",
|
||||
"description": "hook did not export *any* functions (should be cbak, hook)"
|
||||
},
|
||||
{
|
||||
"code": 13,
|
||||
"identifier": "EXPORT_CBAK_FUNC",
|
||||
"description": "hook did not export correct func def int64_t cbak(uint32_t)"
|
||||
},
|
||||
{
|
||||
"code": 14,
|
||||
"identifier": "EXPORT_HOOK_FUNC",
|
||||
"description": "hook did not export correct func def int64_t hook(uint32_t)"
|
||||
},
|
||||
{
|
||||
"code": 15,
|
||||
"identifier": "EXPORT_MISSING",
|
||||
"description": "distinct from export*S*_missing, either hook or cbak is missing"
|
||||
},
|
||||
{
|
||||
"identifier": "FLAGS_INVALID",
|
||||
"code": 16,
|
||||
"description": "HookSet flags were invalid for specified operation "
|
||||
},
|
||||
{
|
||||
"identifier": "FUNCS_MISSING",
|
||||
"code": 17,
|
||||
"description": "hook did not include function code for any functions "
|
||||
},
|
||||
{
|
||||
"identifier": "FUNC_PARAM_INVALID",
|
||||
"code": 18,
|
||||
"description": "parameter types may only be i32 i64 u32 u64 "
|
||||
},
|
||||
{
|
||||
"identifier": "FUNC_RETURN_COUNT",
|
||||
"code": 19,
|
||||
"description": "a function type is defined in the wasm which returns > 1 return value "
|
||||
},
|
||||
{
|
||||
"identifier": "FUNC_RETURN_INVALID",
|
||||
"code": 20,
|
||||
"description": "a function type does not return i32 i64 u32 or u64 "
|
||||
},
|
||||
{
|
||||
"identifier": "FUNC_TYPELESS",
|
||||
"code": 21,
|
||||
"description": "hook defined hook/cbak but their type is not defined in wasm "
|
||||
},
|
||||
{
|
||||
"identifier": "FUNC_TYPE_INVALID",
|
||||
"code": 22,
|
||||
"description": "malformed and illegal wasm in the func type section "
|
||||
},
|
||||
{
|
||||
"identifier": "GRANTS_EMPTY",
|
||||
"code": 23,
|
||||
"description": "HookSet object contained an empty grants array (you should remove it) "
|
||||
},
|
||||
{
|
||||
"identifier": "GRANTS_EXCESS",
|
||||
"code": 24,
|
||||
"description": "HookSet object cotnained a grants array with too many grants "
|
||||
},
|
||||
{
|
||||
"identifier": "GRANTS_FIELD",
|
||||
"code": 25,
|
||||
"description": "HookSet object contained a grant without Authorize or HookHash "
|
||||
},
|
||||
{
|
||||
"identifier": "GRANTS_ILLEGAL",
|
||||
"code": 26,
|
||||
"description": "Hookset object contained grants array which contained a non Grant object "
|
||||
},
|
||||
{
|
||||
"identifier": "GUARD_IMPORT",
|
||||
"code": 27,
|
||||
"description": "guard import is missing "
|
||||
},
|
||||
{
|
||||
"identifier": "GUARD_MISSING",
|
||||
"code": 28,
|
||||
"description": "guard call missing at top of loop "
|
||||
},
|
||||
{
|
||||
"identifier": "GUARD_PARAMETERS",
|
||||
"code": 29,
|
||||
"description": "guard called but did not use constant expressions for params "
|
||||
},
|
||||
{
|
||||
"identifier": "HASH_OR_CODE",
|
||||
"code": 30,
|
||||
"description": "HookSet object can contain only one of CreateCode and HookHash "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOKON_MISSING",
|
||||
"code": 31,
|
||||
"description": "HookSet object did not contain HookOn but should have "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOKS_ARRAY_BAD",
|
||||
"code": 32,
|
||||
"description": "attempt to HookSet with a Hooks array containing a non-Hook obj "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOKS_ARRAY_BLANK",
|
||||
"code": 33,
|
||||
"description": "all hook set objs were blank "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOKS_ARRAY_EMPTY",
|
||||
"code": 34,
|
||||
"description": "attempt to HookSet with an empty Hooks array "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOKS_ARRAY_MISSING",
|
||||
"code": 35,
|
||||
"description": "attempt to HookSet without a Hooks array "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOKS_ARRAY_TOO_BIG",
|
||||
"code": 36,
|
||||
"description": "attempt to HookSet with a Hooks array beyond the chain size limit "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOK_ADD",
|
||||
"code": 37,
|
||||
"description": "Informational: adding ltHook to directory "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOK_DEF_MISSING",
|
||||
"code": 38,
|
||||
"description": "attempt to reference a hook definition (by hash) that is not on ledger "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOK_DELETE",
|
||||
"code": 39,
|
||||
"description": "unable to delete ltHook from owner "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOK_INVALID_FIELD",
|
||||
"code": 40,
|
||||
"description": "HookSetObj contained an illegal/unexpected field "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOK_PARAMS_COUNT",
|
||||
"code": 41,
|
||||
"description": "hookset obj would create too many hook parameters "
|
||||
},
|
||||
{
|
||||
"identifier": "HOOK_PARAM_SIZE",
|
||||
"code": 42,
|
||||
"description": "hookset obj sets a parameter or value that exceeds max allowable size "
|
||||
},
|
||||
{
|
||||
"identifier": "IMPORTS_MISSING",
|
||||
"code": 43,
|
||||
"description": "hook must import guard, and accept/rollback "
|
||||
},
|
||||
{
|
||||
"identifier": "IMPORT_ILLEGAL",
|
||||
"code": 44,
|
||||
"description": "attempted import of a non-whitelisted function "
|
||||
},
|
||||
{
|
||||
"identifier": "IMPORT_MODULE_BAD",
|
||||
"code": 45,
|
||||
"description": "hook attempted to specify no or a bad import module "
|
||||
},
|
||||
{
|
||||
"identifier": "IMPORT_MODULE_ENV",
|
||||
"code": 46,
|
||||
"description": "hook attempted to specify import module not named env "
|
||||
},
|
||||
{
|
||||
"identifier": "IMPORT_NAME_BAD",
|
||||
"code": 47,
|
||||
"description": "import name was too short or too long "
|
||||
},
|
||||
{
|
||||
"identifier": "INSTALL_FLAG",
|
||||
"code": 48,
|
||||
"description": "install operation requires hsoOVERRIDE "
|
||||
},
|
||||
{
|
||||
"identifier": "INSTALL_MISSING",
|
||||
"code": 49,
|
||||
"description": "install operation specifies hookhash which doesn't exist on the ledger "
|
||||
},
|
||||
{
|
||||
"identifier": "INSTRUCTION_COUNT",
|
||||
"code": 50,
|
||||
"description": "worst case execution instruction count as computed by HookSet "
|
||||
},
|
||||
{
|
||||
"identifier": "INSTRUCTION_EXCESS",
|
||||
"code": 51,
|
||||
"description": "worst case execution instruction count was too large "
|
||||
},
|
||||
{
|
||||
"identifier": "MEMORY_GROW",
|
||||
"code": 52,
|
||||
"description": "memory.grow instruction is present but disallowed "
|
||||
},
|
||||
{
|
||||
"identifier": "NAMESPACE_MISSING",
|
||||
"code": 53,
|
||||
"description": "HookSet object lacked HookNamespace "
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE",
|
||||
"code": 54,
|
||||
"description": "Informational: a namespace is being deleted "
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE_ACCOUNT",
|
||||
"code": 55,
|
||||
"description": "nsdelete tried to delete ns from a non-existing account "
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE_COUNT",
|
||||
"code": 56,
|
||||
"description": "namespace state count less than 0 / overflow "
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE_DIR",
|
||||
"code": 57,
|
||||
"description": "could not delete directory node in ledger "
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE_DIRECTORY",
|
||||
"code": 58,
|
||||
"description": "nsdelete operation failed to delete ns directory "
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE_DIR_ENTRY",
|
||||
"code": 59,
|
||||
"description": "nsdelete operation failed due to bad entry in ns directory "
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE_ENTRY",
|
||||
"code": 60,
|
||||
"description": "nsdelete operation failed due to missing hook state entry "
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE_FIELD",
|
||||
"code": 61
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE_FLAGS",
|
||||
"code": 62
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE_NONSTATE",
|
||||
"code": 63,
|
||||
"description": "nsdelete operation failed due to the presence of a non-hookstate obj "
|
||||
},
|
||||
{
|
||||
"identifier": "NSDELETE_NOTHING",
|
||||
"code": 64,
|
||||
"description": "hsfNSDELETE provided but nothing to delete "
|
||||
},
|
||||
{
|
||||
"identifier": "OPERATION_INVALID",
|
||||
"code": 65,
|
||||
"description": "could not deduce an operation from the provided hookset obj "
|
||||
},
|
||||
{
|
||||
"identifier": "OVERRIDE_MISSING",
|
||||
"code": 66,
|
||||
"description": "HookSet object was trying to update or delete a hook but lacked hsfOVERRIDE "
|
||||
},
|
||||
{
|
||||
"identifier": "PARAMETERS_FIELD",
|
||||
"code": 67,
|
||||
"description": "HookParameters contained a HookParameter with an invalid key in it "
|
||||
},
|
||||
{
|
||||
"identifier": "PARAMETERS_ILLEGAL",
|
||||
"code": 68,
|
||||
"description": "HookParameters contained something other than a HookParameter "
|
||||
},
|
||||
{
|
||||
"identifier": "PARAMETERS_NAME",
|
||||
"code": 69,
|
||||
"description": "HookParameters contained a HookParameter which lacked ParameterName field "
|
||||
},
|
||||
{
|
||||
"identifier": "PARAM_HOOK_CBAK",
|
||||
"code": 70,
|
||||
"description": "hook and cbak must take exactly one u32 parameter "
|
||||
},
|
||||
{
|
||||
"identifier": "RETURN_HOOK_CBAK",
|
||||
"code": 71,
|
||||
"description": "hook and cbak must retunr i64 "
|
||||
},
|
||||
{
|
||||
"identifier": "SHORT_HOOK",
|
||||
"code": 72,
|
||||
"description": "web assembly byte code ended abruptly "
|
||||
},
|
||||
{
|
||||
"identifier": "TYPE_INVALID",
|
||||
"code": 73,
|
||||
"description": "malformed and illegal wasm specifying an illegal local var type "
|
||||
},
|
||||
{
|
||||
"identifier": "WASM_BAD_MAGIC",
|
||||
"code": 74,
|
||||
"description": "wasm magic number missing or not wasm "
|
||||
},
|
||||
{
|
||||
"identifier": "WASM_INVALID",
|
||||
"code": 75,
|
||||
"description": "set hook operation would set invalid wasm "
|
||||
},
|
||||
{
|
||||
"identifier": "WASM_PARSE_LOOP",
|
||||
"code": 76,
|
||||
"description": "wasm section parsing resulted in an infinite loop "
|
||||
},
|
||||
{
|
||||
"identifier": "WASM_SMOKE_TEST",
|
||||
"code": 77,
|
||||
"description": "Informational: first attempt to load wasm into wasm runtime "
|
||||
},
|
||||
{
|
||||
"identifier": "WASM_TEST_FAILURE",
|
||||
"code": 78,
|
||||
"description": "the smoke test failed "
|
||||
},
|
||||
{
|
||||
"identifier": "WASM_TOO_BIG",
|
||||
"code": 79,
|
||||
"description": "set hook would exceed maximum hook size "
|
||||
},
|
||||
{
|
||||
"identifier": "WASM_TOO_SMALL",
|
||||
"code": 80
|
||||
},
|
||||
{
|
||||
"identifier": "WASM_VALIDATION",
|
||||
"code": 81,
|
||||
"description": "a generic error while parsing wasm, usually leb128 overflow"
|
||||
},
|
||||
{
|
||||
"identifier": "HOOK_CBAK_DIFF_TYPES",
|
||||
"code": 82,
|
||||
"description": "hook and cbak function definitions were different"
|
||||
}
|
||||
]
|
||||
@@ -6,7 +6,7 @@
|
||||
"DestinationTag": 13,
|
||||
"Fee": "2000000",
|
||||
"Sequence": 2470665,
|
||||
"Flags": 2147483648
|
||||
"Flags": "2147483648"
|
||||
},
|
||||
{
|
||||
"TransactionType": "AccountSet",
|
||||
@@ -48,7 +48,7 @@
|
||||
"Account": "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8",
|
||||
"Authorize": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de",
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"Flags": "2147483648",
|
||||
"Sequence": 2
|
||||
},
|
||||
{
|
||||
@@ -109,7 +109,9 @@
|
||||
"Fee": "10",
|
||||
"NFTokenOffers": {
|
||||
"$type": "json",
|
||||
"$value": ["4AAAEEA76E3C8148473CB3840CE637676E561FB02BD4CA22CA59729EA815B862"]
|
||||
"$value": [
|
||||
"4AAAEEA76E3C8148473CB3840CE637676E561FB02BD4CA22CA59729EA815B862"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -120,7 +122,7 @@
|
||||
"$value": "100",
|
||||
"$type": "xrp"
|
||||
},
|
||||
"Flags": 1,
|
||||
"Flags": "1",
|
||||
"Destination": "",
|
||||
"Fee": "10"
|
||||
},
|
||||
@@ -128,7 +130,7 @@
|
||||
"TransactionType": "OfferCancel",
|
||||
"Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"Fee": "12",
|
||||
"Flags": 0,
|
||||
"Flags": "0",
|
||||
"LastLedgerSequence": 7108629,
|
||||
"OfferSequence": 6,
|
||||
"Sequence": 7
|
||||
@@ -137,7 +139,7 @@
|
||||
"TransactionType": "OfferCreate",
|
||||
"Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"Fee": "12",
|
||||
"Flags": 0,
|
||||
"Flags": "0",
|
||||
"LastLedgerSequence": 7108682,
|
||||
"Sequence": 8,
|
||||
"TakerGets": "6000000",
|
||||
@@ -155,7 +157,7 @@
|
||||
"$type": "xrp"
|
||||
},
|
||||
"Fee": "12",
|
||||
"Flags": 2147483648,
|
||||
"Flags": "2147483648",
|
||||
"Sequence": 2
|
||||
},
|
||||
{
|
||||
@@ -185,14 +187,14 @@
|
||||
"Fee": "10"
|
||||
},
|
||||
{
|
||||
"Flags": 0,
|
||||
"Flags": "0",
|
||||
"TransactionType": "SetRegularKey",
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Fee": "12",
|
||||
"RegularKey": "rAR8rR8sUkBoCZFawhkWzY4Y5YoyuznwD"
|
||||
},
|
||||
{
|
||||
"Flags": 0,
|
||||
"Flags": "0",
|
||||
"TransactionType": "SignerListSet",
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Fee": "12",
|
||||
@@ -232,7 +234,7 @@
|
||||
"TransactionType": "TrustSet",
|
||||
"Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"Fee": "12",
|
||||
"Flags": 262144,
|
||||
"Flags": "262144",
|
||||
"LastLedgerSequence": 8007750,
|
||||
"LimitAmount": {
|
||||
"$type": "json",
|
||||
@@ -244,4 +246,4 @@
|
||||
},
|
||||
"Sequence": 12
|
||||
}
|
||||
]
|
||||
]
|
||||
@@ -7,6 +7,7 @@ import { Link } from '../../components'
|
||||
import { ref } from 'valtio'
|
||||
import estimateFee from '../../utils/estimateFee'
|
||||
import { SetHookData } from '../../utils/setHook'
|
||||
import ResultLink from '../../components/ResultLink'
|
||||
|
||||
export const sha256 = async (string: string) => {
|
||||
const utf8 = new TextEncoder().encode(string)
|
||||
@@ -144,6 +145,25 @@ export const deployHook = async (account: IAccount & { name?: string }, data: Se
|
||||
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',
|
||||
@@ -151,27 +171,17 @@ export const deployHook = async (account: IAccount & { name?: string }, data: Se
|
||||
})
|
||||
state.deployLogs.push({
|
||||
type: 'success',
|
||||
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}`,
|
||||
message: resultMsg
|
||||
})
|
||||
} else if (submitRes.engine_result) {
|
||||
state.deployLogs.push({
|
||||
type: 'error',
|
||||
message: resultMsg
|
||||
})
|
||||
} else {
|
||||
state.deployLogs.push({
|
||||
type: 'error',
|
||||
message: `[${submitRes.engine_result || submitRes.error}] ${
|
||||
submitRes.engine_result_message || submitRes.error_exception
|
||||
}`
|
||||
message: `[${submitRes.error}] ${submitRes.error_exception}`
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
77
state/actions/sendTransaction.tsx
Normal file
77
state/actions/sendTransaction.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
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`
|
||||
})
|
||||
}
|
||||
}
|
||||
79
state/constants/flags.ts
Normal file
79
state/constants/flags.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { SelectOption } from '../transactions';
|
||||
|
||||
interface Flags {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export const transactionFlags: { [key: /* TransactionType */ string]: Flags } = {
|
||||
"*": {
|
||||
tfFullyCanonicalSig: '0x80000000'
|
||||
},
|
||||
Payment: {
|
||||
tfNoDirectRipple: '0x00010000',
|
||||
tfPartialPayment: '0x00020000',
|
||||
tfLimitQuality: '0x00040000',
|
||||
},
|
||||
AccountSet: {
|
||||
tfRequireDestTag: '0x00010000',
|
||||
tfOptionalDestTag: '0x00020000',
|
||||
tfRequireAuth: '0x00040000',
|
||||
tfOptionalAuth: '0x00080000',
|
||||
tfDisallowXRP: '0x00100000',
|
||||
tfAllowXRP: '0x00200000',
|
||||
},
|
||||
NFTokenCreateOffer: {
|
||||
tfSellNFToken: '0x00000001',
|
||||
},
|
||||
NFTokenMint: {
|
||||
tfBurnable: '0x00000001',
|
||||
tfOnlyXRP: '0x00000002',
|
||||
tfTrustLine: '0x00000004',
|
||||
tfTransferable: '0x00000008',
|
||||
},
|
||||
OfferCreate: {
|
||||
tfPassive: '0x00010000',
|
||||
tfImmediateOrCancel: '0x00020000',
|
||||
tfFillOrKill: '0x00040000',
|
||||
tfSell: '0x00080000',
|
||||
},
|
||||
PaymentChannelClaim: {
|
||||
tfRenew: '0x00010000',
|
||||
tfClose: '0x00020000',
|
||||
},
|
||||
TrustSet: {
|
||||
tfSetfAuth: '0x00010000',
|
||||
tfSetNoRipple: '0x00020000',
|
||||
tfClearNoRipple: '0x00040000',
|
||||
tfSetFreeze: '0x00100000',
|
||||
tfClearFreeze: '0x00200000',
|
||||
},
|
||||
}
|
||||
|
||||
export const getFlags = (tt?: string) => {
|
||||
if (!tt) return
|
||||
const flags = {
|
||||
...transactionFlags['*'],
|
||||
...transactionFlags[tt]
|
||||
}
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
|
||||
export function combineFlags(flags?: string[]): string | undefined {
|
||||
if (!flags) return
|
||||
|
||||
const num = flags.reduce((cumm, curr) => cumm | BigInt(curr), BigInt(0))
|
||||
return num.toString()
|
||||
}
|
||||
|
||||
export function extractFlags(transactionType: string, flags?: string | number,): SelectOption[] {
|
||||
const flagsObj = getFlags(transactionType)
|
||||
if (!flags || !flagsObj) return []
|
||||
|
||||
const extracted = Object.entries(flagsObj).reduce((cumm, [label, value]) => {
|
||||
return (BigInt(flags) & BigInt(value)) ? cumm.concat({ label, value }) : cumm
|
||||
}, [] as SelectOption[])
|
||||
|
||||
return extracted
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import transactionsData from '../content/transactions.json'
|
||||
import state from '.'
|
||||
import { showAlert } from '../state/actions/showAlert'
|
||||
import { parseJSON } from '../utils/json'
|
||||
import { extractFlags, getFlags } from './constants/flags'
|
||||
|
||||
export type SelectOption = {
|
||||
value: string
|
||||
@@ -14,6 +15,7 @@ export interface TransactionState {
|
||||
selectedTransaction: SelectOption | null
|
||||
selectedAccount: SelectOption | null
|
||||
selectedDestAccount: SelectOption | null
|
||||
selectedFlags: SelectOption[] | null
|
||||
txIsLoading: boolean
|
||||
txIsDisabled: boolean
|
||||
txFields: TxFields
|
||||
@@ -31,6 +33,7 @@ export const defaultTransaction: TransactionState = {
|
||||
selectedTransaction: null,
|
||||
selectedAccount: null,
|
||||
selectedDestAccount: null,
|
||||
selectedFlags: null,
|
||||
txIsLoading: false,
|
||||
txIsDisabled: false,
|
||||
txFields: {},
|
||||
@@ -128,9 +131,8 @@ export const prepareTransaction = (data: any) => {
|
||||
try {
|
||||
options[field] = JSON.parse(_value.$value)
|
||||
} catch (error) {
|
||||
const message = `Input error for json field '${field}': ${
|
||||
error instanceof Error ? error.message : ''
|
||||
}`
|
||||
const message = `Input error for json field '${field}': ${error instanceof Error ? error.message : ''
|
||||
}`
|
||||
console.error(message)
|
||||
options[field] = _value.$value
|
||||
}
|
||||
@@ -205,6 +207,13 @@ export const prepareState = (value: string, transactionType?: string) => {
|
||||
rest.Destination = Destination
|
||||
}
|
||||
|
||||
if (getFlags(TransactionType) && rest.Flags) {
|
||||
const flags = extractFlags(TransactionType, rest.Flags)
|
||||
|
||||
rest.Flags = undefined
|
||||
tx.selectedFlags = flags
|
||||
}
|
||||
|
||||
Object.keys(rest).forEach(field => {
|
||||
const value = rest[field]
|
||||
const schemaVal = schema[field as keyof TxFields]
|
||||
|
||||
@@ -2725,9 +2725,9 @@ javascript-time-ago@^2.3.11:
|
||||
relative-time-format "^1.0.7"
|
||||
|
||||
jose@^4.1.4, jose@^4.3.7:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.npmjs.org/jose/-/jose-4.6.0.tgz"
|
||||
integrity sha512-0hNAkhMBNi4soKSAX4zYOFV+aqJlEz/4j4fregvasJzEVtjDChvWqRjPvHwLqr5hx28Ayr6bsOs1Kuj87V0O8w==
|
||||
version "4.10.0"
|
||||
resolved "https://registry.yarnpkg.com/jose/-/jose-4.10.0.tgz#2e0b7bcc80dd0775f8a4588e55beb9460c37d60a"
|
||||
integrity sha512-KEhB/eLGLomWGPTb+/RNbYsTjIyx03JmbqAyIyiXBuNSa7CmNrJd5ysFhblayzs/e/vbOPMUaLnjHUMhGp4yLw==
|
||||
|
||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
||||
Reference in New Issue
Block a user