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