Compare commits
	
		
			14 Commits
		
	
	
		
			feat/tx-pa
			...
			fix/nft-cr
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					3340857575 | ||
| 
						 | 
					e1f34c4beb | ||
| 
						 | 
					54a89c969e | ||
| 
						 | 
					ded867d997 | ||
| 
						 | 
					0fce9af77c | ||
| 
						 | 
					55c68c580a | ||
| 
						 | 
					832a7997d1 | ||
| 
						 | 
					4528e5a16e | ||
| 
						 | 
					38f064c6d8 | ||
| 
						 | 
					fbf4565dbc | ||
| 
						 | 
					9001c64fed | ||
| 
						 | 
					03b768db4e | ||
| 
						 | 
					825af0db89 | ||
| 
						 | 
					31043f33ab | 
							
								
								
									
										71
									
								
								components/Sequence.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								components/Sequence.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
import { FC, useCallback, useState } from 'react'
 | 
			
		||||
import state from '../state'
 | 
			
		||||
import { Flex, Input, Button } from '.'
 | 
			
		||||
import fetchAccountInfo from '../utils/accountInfo'
 | 
			
		||||
import { useSnapshot } from 'valtio'
 | 
			
		||||
 | 
			
		||||
interface AccountSequenceProps {
 | 
			
		||||
  address?: string
 | 
			
		||||
}
 | 
			
		||||
const AccountSequence: FC<AccountSequenceProps> = ({ address }) => {
 | 
			
		||||
  const { accounts } = useSnapshot(state)
 | 
			
		||||
  const account = accounts.find(acc => acc.address === address)
 | 
			
		||||
  const [isLoading, setIsLoading] = useState(false)
 | 
			
		||||
  const setSequence = useCallback(
 | 
			
		||||
    (sequence: number) => {
 | 
			
		||||
      const acc = state.accounts.find(acc => acc.address == address)
 | 
			
		||||
      if (!acc) return
 | 
			
		||||
      acc.sequence = sequence
 | 
			
		||||
    },
 | 
			
		||||
    [address]
 | 
			
		||||
  )
 | 
			
		||||
  const handleUpdateSequence = useCallback(
 | 
			
		||||
    async (silent?: boolean) => {
 | 
			
		||||
      if (!account) return
 | 
			
		||||
      setIsLoading(true)
 | 
			
		||||
 | 
			
		||||
      const info = await fetchAccountInfo(account.address, { silent })
 | 
			
		||||
      if (info) {
 | 
			
		||||
        setSequence(info.Sequence)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      setIsLoading(false)
 | 
			
		||||
    },
 | 
			
		||||
    [account, setSequence]
 | 
			
		||||
  )
 | 
			
		||||
  const disabled = !account
 | 
			
		||||
  return (
 | 
			
		||||
    <Flex row align="center" fluid>
 | 
			
		||||
      <Input
 | 
			
		||||
        placeholder="Account sequence"
 | 
			
		||||
        value={account?.sequence || ""}
 | 
			
		||||
        disabled={!account}
 | 
			
		||||
        type="number"
 | 
			
		||||
        readOnly={true}
 | 
			
		||||
      />
 | 
			
		||||
      <Button
 | 
			
		||||
        size="xs"
 | 
			
		||||
        variant="primary"
 | 
			
		||||
        type="button"
 | 
			
		||||
        outline
 | 
			
		||||
        disabled={disabled}
 | 
			
		||||
        isDisabled={disabled}
 | 
			
		||||
        isLoading={isLoading}
 | 
			
		||||
        css={{
 | 
			
		||||
          background: '$backgroundAlt',
 | 
			
		||||
          position: 'absolute',
 | 
			
		||||
          right: '$2',
 | 
			
		||||
          fontSize: '$xs',
 | 
			
		||||
          cursor: 'pointer',
 | 
			
		||||
          alignContent: 'center',
 | 
			
		||||
          display: 'flex'
 | 
			
		||||
        }}
 | 
			
		||||
        onClick={() => handleUpdateSequence()}
 | 
			
		||||
      >
 | 
			
		||||
        Update
 | 
			
		||||
      </Button>
 | 
			
		||||
    </Flex>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default AccountSequence
 | 
			
		||||
@@ -21,6 +21,7 @@ import { prepareDeployHookTx, sha256 } from '../state/actions/deployHook'
 | 
			
		||||
import estimateFee from '../utils/estimateFee'
 | 
			
		||||
import { getParameters, getInvokeOptions, transactionOptions, SetHookData } from '../utils/setHook'
 | 
			
		||||
import { capitalize } from '../utils/helpers'
 | 
			
		||||
import AccountSequence from './Sequence'
 | 
			
		||||
 | 
			
		||||
export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo(
 | 
			
		||||
  ({ accountAddress }) => {
 | 
			
		||||
@@ -190,6 +191,10 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo(
 | 
			
		||||
                    onChange={(acc: any) => setSelectedAccount(acc)}
 | 
			
		||||
                  />
 | 
			
		||||
                </Box>
 | 
			
		||||
                <Box css={{ width: '100%', position: 'relative' }}>
 | 
			
		||||
                  <Label>Sequence</Label>
 | 
			
		||||
                  <AccountSequence address={selectedAccount?.value} />
 | 
			
		||||
                </Box>
 | 
			
		||||
                <Box css={{ width: '100%' }}>
 | 
			
		||||
                  <Label>Invoke on transactions</Label>
 | 
			
		||||
                  <Controller
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,8 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
        selectedAccount,
 | 
			
		||||
        txFields,
 | 
			
		||||
        selectedFlags,
 | 
			
		||||
        hookParameters
 | 
			
		||||
        hookParameters,
 | 
			
		||||
        memos
 | 
			
		||||
      } = state
 | 
			
		||||
 | 
			
		||||
      const TransactionType = selectedTransaction?.value || null
 | 
			
		||||
@@ -61,6 +62,13 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
          HookParameter: { HookParameterName: toHex(label), HookParameterValue: toHex(value) }
 | 
			
		||||
        })
 | 
			
		||||
      }, [])
 | 
			
		||||
      const Memos = memos
 | 
			
		||||
        ? Object.entries(memos).reduce<SetHookData['Memos']>((acc, [_, { format, data, type }]) => {
 | 
			
		||||
            return acc?.concat({
 | 
			
		||||
              Memo: { MemoData: toHex(data), MemoFormat: toHex(format), MemoType: toHex(type) }
 | 
			
		||||
            })
 | 
			
		||||
          }, [])
 | 
			
		||||
        : undefined
 | 
			
		||||
 | 
			
		||||
      return prepareTransaction({
 | 
			
		||||
        ...txFields,
 | 
			
		||||
@@ -68,7 +76,8 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
        Flags,
 | 
			
		||||
        TransactionType,
 | 
			
		||||
        Destination,
 | 
			
		||||
        Account
 | 
			
		||||
        Account,
 | 
			
		||||
        Memos
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    [txState]
 | 
			
		||||
@@ -84,15 +93,29 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
    }
 | 
			
		||||
  }, [selectedAccount?.value, selectedTransaction?.value, setState, txIsLoading])
 | 
			
		||||
 | 
			
		||||
  const getJsonString = useCallback(
 | 
			
		||||
    (state?: Partial<TransactionState>) =>
 | 
			
		||||
      JSON.stringify(prepareOptions?.(state) || {}, null, editorSettings.tabSize),
 | 
			
		||||
    [editorSettings.tabSize, prepareOptions]
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const saveEditorState = useCallback(
 | 
			
		||||
    (value: string = '', transactionType?: string) => {
 | 
			
		||||
      const pTx = prepareState(value, transactionType)
 | 
			
		||||
      if (pTx) {
 | 
			
		||||
        pTx.editorValue = getJsonString(pTx)
 | 
			
		||||
        return setState(pTx)
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    [getJsonString, setState]
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const submitTest = useCallback(async () => {
 | 
			
		||||
    let st: TransactionState | undefined
 | 
			
		||||
    const tt = txState.selectedTransaction?.value
 | 
			
		||||
    if (viewType === 'json') {
 | 
			
		||||
      // save the editor state first
 | 
			
		||||
      const pst = prepareState(editorValue || '', tt)
 | 
			
		||||
      if (!pst) return
 | 
			
		||||
 | 
			
		||||
      st = setState(pst)
 | 
			
		||||
      st = saveEditorState(editorValue, tt)
 | 
			
		||||
      if (!st) return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const account = accounts.find(acc => acc.address === selectedAccount?.value)
 | 
			
		||||
@@ -123,23 +146,18 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
    }
 | 
			
		||||
    setState({ txIsLoading: false })
 | 
			
		||||
  }, [
 | 
			
		||||
    txState.selectedTransaction?.value,
 | 
			
		||||
    viewType,
 | 
			
		||||
    accounts,
 | 
			
		||||
    txIsDisabled,
 | 
			
		||||
    setState,
 | 
			
		||||
    header,
 | 
			
		||||
    saveEditorState,
 | 
			
		||||
    editorValue,
 | 
			
		||||
    txState,
 | 
			
		||||
    selectedAccount?.value,
 | 
			
		||||
    prepareOptions
 | 
			
		||||
  ])
 | 
			
		||||
 | 
			
		||||
  const getJsonString = useCallback(
 | 
			
		||||
    (state?: Partial<TransactionState>) =>
 | 
			
		||||
      JSON.stringify(prepareOptions?.(state) || {}, null, editorSettings.tabSize),
 | 
			
		||||
    [editorSettings.tabSize, prepareOptions]
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const resetState = useCallback(
 | 
			
		||||
    (transactionType: SelectOption | undefined = defaultTransactionType) => {
 | 
			
		||||
      const fields = getTxFields(transactionType?.value)
 | 
			
		||||
@@ -192,11 +210,21 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
    [accounts, prepareOptions, setState, txState]
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const switchToJson = useCallback(() => {
 | 
			
		||||
    const editorValue = getJsonString()
 | 
			
		||||
    setState({ viewType: 'json', editorValue })
 | 
			
		||||
  }, [getJsonString, setState])
 | 
			
		||||
 | 
			
		||||
  const switchToUI = useCallback(() => {
 | 
			
		||||
    setState({ viewType: 'ui' })
 | 
			
		||||
  }, [setState])
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Box css={{ position: 'relative', height: 'calc(100% - 28px)' }} {...props}>
 | 
			
		||||
      {viewType === 'json' ? (
 | 
			
		||||
        <TxJson
 | 
			
		||||
          getJsonString={getJsonString}
 | 
			
		||||
          saveEditorState={saveEditorState}
 | 
			
		||||
          header={header}
 | 
			
		||||
          state={txState}
 | 
			
		||||
          setState={setState}
 | 
			
		||||
@@ -204,6 +232,7 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
        />
 | 
			
		||||
      ) : (
 | 
			
		||||
        <TxUI
 | 
			
		||||
          switchToJson={switchToJson}
 | 
			
		||||
          state={txState}
 | 
			
		||||
          resetState={resetState}
 | 
			
		||||
          setState={setState}
 | 
			
		||||
@@ -224,8 +253,8 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
        <Button
 | 
			
		||||
          onClick={() => {
 | 
			
		||||
            if (viewType === 'ui') {
 | 
			
		||||
              setState({ viewType: 'json' })
 | 
			
		||||
            } else setState({ viewType: 'ui' })
 | 
			
		||||
              switchToJson()
 | 
			
		||||
            } else switchToUI()
 | 
			
		||||
          }}
 | 
			
		||||
          outline
 | 
			
		||||
        >
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react'
 | 
			
		||||
import { FC, useCallback, useEffect, useState } from 'react'
 | 
			
		||||
import { useSnapshot } from 'valtio'
 | 
			
		||||
import state, { prepareState, transactionsData, TransactionState } from '../../state'
 | 
			
		||||
import state, { transactionsData, TransactionState } from '../../state'
 | 
			
		||||
import Text from '../Text'
 | 
			
		||||
import { Flex, Link } from '..'
 | 
			
		||||
import { showAlert } from '../../state/actions/showAlert'
 | 
			
		||||
@@ -11,27 +11,27 @@ import Monaco from '../Monaco'
 | 
			
		||||
import type monaco from 'monaco-editor'
 | 
			
		||||
 | 
			
		||||
interface JsonProps {
 | 
			
		||||
  getJsonString?: (state?: Partial<TransactionState>) => string
 | 
			
		||||
  getJsonString: (st?: Partial<TransactionState>) => string
 | 
			
		||||
  saveEditorState: (val?: string, tt?: string) => TransactionState | undefined
 | 
			
		||||
  header?: string
 | 
			
		||||
  setState: (pTx?: Partial<TransactionState> | undefined) => void
 | 
			
		||||
  state: TransactionState
 | 
			
		||||
  estimateFee?: () => Promise<string | undefined>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const TxJson: FC<JsonProps> = ({ getJsonString, state: txState, header, setState }) => {
 | 
			
		||||
export const TxJson: FC<JsonProps> = ({
 | 
			
		||||
  getJsonString,
 | 
			
		||||
  state: txState,
 | 
			
		||||
  header,
 | 
			
		||||
  setState,
 | 
			
		||||
  saveEditorState
 | 
			
		||||
}) => {
 | 
			
		||||
  const { editorSettings, accounts } = useSnapshot(state)
 | 
			
		||||
  const { editorValue, estimatedFee } = txState
 | 
			
		||||
  const { editorValue, estimatedFee, editorIsSaved } = txState
 | 
			
		||||
  const [currTxType, setCurrTxType] = useState<string | undefined>(
 | 
			
		||||
    txState.selectedTransaction?.value
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setState({
 | 
			
		||||
      editorValue: getJsonString?.()
 | 
			
		||||
    })
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, [])
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const parsed = parseJSON(editorValue)
 | 
			
		||||
    if (!parsed) return
 | 
			
		||||
@@ -44,29 +44,19 @@ export const TxJson: FC<JsonProps> = ({ getJsonString, state: txState, header, s
 | 
			
		||||
    }
 | 
			
		||||
  }, [editorValue])
 | 
			
		||||
 | 
			
		||||
  const saveState = (value: string, transactionType?: string) => {
 | 
			
		||||
    const tx = prepareState(value, transactionType)
 | 
			
		||||
    if (tx) {
 | 
			
		||||
      setState(tx)
 | 
			
		||||
      setState({
 | 
			
		||||
        editorValue: getJsonString?.(tx)
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const discardChanges = () => {
 | 
			
		||||
    showAlert('Confirm', {
 | 
			
		||||
      body: 'Are you sure to discard these changes?',
 | 
			
		||||
      confirmText: 'Yes',
 | 
			
		||||
      onCancel: () => {},
 | 
			
		||||
      onConfirm: () => setState({ editorValue: getJsonString?.() })
 | 
			
		||||
      onConfirm: () => setState({ editorValue: getJsonString() })
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const onExit = (value: string) => {
 | 
			
		||||
    const options = parseJSON(value)
 | 
			
		||||
    if (options) {
 | 
			
		||||
      saveState(value, currTxType)
 | 
			
		||||
      saveEditorState(value, currTxType)
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    showAlert('Error!', {
 | 
			
		||||
@@ -163,8 +153,6 @@ export const TxJson: FC<JsonProps> = ({ getJsonString, state: txState, header, s
 | 
			
		||||
    })
 | 
			
		||||
  }, [getSchemas, monacoInst])
 | 
			
		||||
 | 
			
		||||
  const hasUnsaved = useMemo(() => editorValue !== getJsonString?.(), [editorValue, getJsonString])
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Monaco
 | 
			
		||||
      rootProps={{
 | 
			
		||||
@@ -174,7 +162,7 @@ export const TxJson: FC<JsonProps> = ({ getJsonString, state: txState, header, s
 | 
			
		||||
      id={header}
 | 
			
		||||
      height="100%"
 | 
			
		||||
      value={editorValue}
 | 
			
		||||
      onChange={val => setState({ editorValue: val })}
 | 
			
		||||
      onChange={val => setState({ editorValue: val, editorIsSaved: false })}
 | 
			
		||||
      onMount={(editor, monaco) => {
 | 
			
		||||
        editor.updateOptions({
 | 
			
		||||
          minimap: { enabled: false },
 | 
			
		||||
@@ -190,12 +178,12 @@ export const TxJson: FC<JsonProps> = ({ getJsonString, state: txState, header, s
 | 
			
		||||
        model?.onWillDispose(() => onExit(model.getValue()))
 | 
			
		||||
      }}
 | 
			
		||||
      overlay={
 | 
			
		||||
        hasUnsaved ? (
 | 
			
		||||
        !editorIsSaved ? (
 | 
			
		||||
          <Flex row align="center" css={{ fontSize: '$xs', color: '$textMuted', ml: 'auto' }}>
 | 
			
		||||
            <Text muted small>
 | 
			
		||||
              This file has unsaved changes.
 | 
			
		||||
            </Text>
 | 
			
		||||
            <Link css={{ ml: '$1' }} onClick={() => saveState(editorValue || '', currTxType)}>
 | 
			
		||||
            <Link css={{ ml: '$1' }} onClick={() => saveEditorState(editorValue, currTxType)}>
 | 
			
		||||
              save
 | 
			
		||||
            </Link>
 | 
			
		||||
            <Link css={{ ml: '$1' }} onClick={discardChanges}>
 | 
			
		||||
 
 | 
			
		||||
@@ -19,15 +19,23 @@ import { Button } from '..'
 | 
			
		||||
import Textarea from '../Textarea'
 | 
			
		||||
import { getFlags } from '../../state/constants/flags'
 | 
			
		||||
import { Plus, Trash } from 'phosphor-react'
 | 
			
		||||
import AccountSequence from '../Sequence'
 | 
			
		||||
 | 
			
		||||
interface UIProps {
 | 
			
		||||
  setState: (pTx?: Partial<TransactionState> | undefined) => TransactionState | undefined
 | 
			
		||||
  resetState: (tt?: SelectOption) => TransactionState | undefined
 | 
			
		||||
  state: TransactionState
 | 
			
		||||
  estimateFee?: (...arg: any) => Promise<string | undefined>
 | 
			
		||||
  switchToJson: () => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const TxUI: FC<UIProps> = ({ state: txState, setState, resetState, estimateFee }) => {
 | 
			
		||||
export const TxUI: FC<UIProps> = ({
 | 
			
		||||
  state: txState,
 | 
			
		||||
  setState,
 | 
			
		||||
  resetState,
 | 
			
		||||
  estimateFee,
 | 
			
		||||
  switchToJson
 | 
			
		||||
}) => {
 | 
			
		||||
  const { accounts } = useSnapshot(state)
 | 
			
		||||
  const {
 | 
			
		||||
    selectedAccount,
 | 
			
		||||
@@ -35,7 +43,8 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, resetState, estima
 | 
			
		||||
    selectedTransaction,
 | 
			
		||||
    txFields,
 | 
			
		||||
    selectedFlags,
 | 
			
		||||
    hookParameters
 | 
			
		||||
    hookParameters,
 | 
			
		||||
    memos
 | 
			
		||||
  } = txState
 | 
			
		||||
 | 
			
		||||
  const accountOptions: SelectOption[] = accounts.map(acc => ({
 | 
			
		||||
@@ -101,8 +110,6 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, resetState, estima
 | 
			
		||||
    [handleEstimateFee, resetState, setState]
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const switchToJson = () => setState({ viewType: 'json' })
 | 
			
		||||
 | 
			
		||||
  // default tx
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (selectedTransaction?.value) return
 | 
			
		||||
@@ -117,7 +124,7 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, resetState, estima
 | 
			
		||||
    [selectedTransaction?.value]
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const richFields = ['TransactionType', 'Account', 'HookParameters']
 | 
			
		||||
  const richFields = ['TransactionType', 'Account', 'HookParameters', 'Memos']
 | 
			
		||||
  if (fields.Destination !== undefined) {
 | 
			
		||||
    richFields.push('Destination')
 | 
			
		||||
  }
 | 
			
		||||
@@ -155,6 +162,9 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, resetState, estima
 | 
			
		||||
            onChange={(acc: any) => handleSetAccount(acc)} // TODO make react-select have correct types for acc
 | 
			
		||||
          />
 | 
			
		||||
        </TxField>
 | 
			
		||||
        <TxField label="Sequence">
 | 
			
		||||
          <AccountSequence address={selectedAccount?.value} />
 | 
			
		||||
        </TxField>
 | 
			
		||||
        {richFields.includes('Destination') && (
 | 
			
		||||
          <TxField label="Destination account">
 | 
			
		||||
            <Select
 | 
			
		||||
@@ -333,6 +343,83 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, resetState, estima
 | 
			
		||||
            </Button>
 | 
			
		||||
          </Flex>
 | 
			
		||||
        </TxField>
 | 
			
		||||
        <TxField multiLine label="Memos">
 | 
			
		||||
          <Flex column fluid>
 | 
			
		||||
            {Object.entries(memos).map(([id, memo]) => (
 | 
			
		||||
              <Flex column key={id} css={{ mb: '$2' }}>
 | 
			
		||||
                <Flex
 | 
			
		||||
                  row
 | 
			
		||||
                  css={{
 | 
			
		||||
                    flexWrap: 'wrap',
 | 
			
		||||
                    width: '100%'
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  <Input
 | 
			
		||||
                    placeholder="Memo type"
 | 
			
		||||
                    value={memo.type}
 | 
			
		||||
                    onChange={e => {
 | 
			
		||||
                      setState({
 | 
			
		||||
                        memos: {
 | 
			
		||||
                          ...memos,
 | 
			
		||||
                          [id]: { ...memo, type: e.target.value }
 | 
			
		||||
                        }
 | 
			
		||||
                      })
 | 
			
		||||
                    }}
 | 
			
		||||
                  />
 | 
			
		||||
                  <Input
 | 
			
		||||
                    placeholder="Data"
 | 
			
		||||
                    css={{ mx: '$2' }}
 | 
			
		||||
                    value={memo.data}
 | 
			
		||||
                    onChange={e => {
 | 
			
		||||
                      setState({
 | 
			
		||||
                        memos: {
 | 
			
		||||
                          ...memos,
 | 
			
		||||
                          [id]: { ...memo, data: e.target.value }
 | 
			
		||||
                        }
 | 
			
		||||
                      })
 | 
			
		||||
                    }}
 | 
			
		||||
                  />
 | 
			
		||||
                  <Input
 | 
			
		||||
                    placeholder="Format"
 | 
			
		||||
                    value={memo.format}
 | 
			
		||||
                    onChange={e => {
 | 
			
		||||
                      setState({
 | 
			
		||||
                        memos: {
 | 
			
		||||
                          ...memos,
 | 
			
		||||
                          [id]: { ...memo, format: e.target.value }
 | 
			
		||||
                        }
 | 
			
		||||
                      })
 | 
			
		||||
                    }}
 | 
			
		||||
                  />
 | 
			
		||||
                  <Button
 | 
			
		||||
                    css={{ ml: '$2' }}
 | 
			
		||||
                    onClick={() => {
 | 
			
		||||
                      const { [id]: _, ...rest } = memos
 | 
			
		||||
                      setState({ memos: rest })
 | 
			
		||||
                    }}
 | 
			
		||||
                    variant="destroy"
 | 
			
		||||
                  >
 | 
			
		||||
                    <Trash weight="regular" size="16px" />
 | 
			
		||||
                  </Button>
 | 
			
		||||
                </Flex>
 | 
			
		||||
              </Flex>
 | 
			
		||||
            ))}
 | 
			
		||||
            <Button
 | 
			
		||||
              outline
 | 
			
		||||
              fullWidth
 | 
			
		||||
              type="button"
 | 
			
		||||
              onClick={() => {
 | 
			
		||||
                const id = Object.keys(memos).length
 | 
			
		||||
                setState({
 | 
			
		||||
                  memos: { ...memos, [id]: { data: '', format: '', type: '' } }
 | 
			
		||||
                })
 | 
			
		||||
              }}
 | 
			
		||||
            >
 | 
			
		||||
              <Plus size="16px" />
 | 
			
		||||
              Add Memo
 | 
			
		||||
            </Button>
 | 
			
		||||
          </Flex>
 | 
			
		||||
        </TxField>
 | 
			
		||||
      </Flex>
 | 
			
		||||
    </Container>
 | 
			
		||||
  )
 | 
			
		||||
 
 | 
			
		||||
@@ -124,7 +124,8 @@
 | 
			
		||||
    },
 | 
			
		||||
    "Flags": "1",
 | 
			
		||||
    "Destination": "",
 | 
			
		||||
    "Fee": "10"
 | 
			
		||||
    "Fee": "10",
 | 
			
		||||
    "Owner": ""
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "TransactionType": "OfferCancel",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import toast from 'react-hot-toast'
 | 
			
		||||
import state, { FaucetAccountRes } from '../index'
 | 
			
		||||
import fetchAccountInfo from '../../utils/accountInfo';
 | 
			
		||||
 | 
			
		||||
export const names = [
 | 
			
		||||
  'Alice',
 | 
			
		||||
@@ -35,40 +36,37 @@ export const addFaucetAccount = async (name?: string, showToast: boolean = false
 | 
			
		||||
  })
 | 
			
		||||
  const json: FaucetAccountRes | { error: string } = await res.json()
 | 
			
		||||
  if ('error' in json) {
 | 
			
		||||
    if (showToast) {
 | 
			
		||||
      return toast.error(json.error, { id: toastId })
 | 
			
		||||
    } else {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    if (showToast) {
 | 
			
		||||
      toast.success('New account created', { id: toastId })
 | 
			
		||||
    }
 | 
			
		||||
    const currNames = state.accounts.map(acc => acc.name)
 | 
			
		||||
    state.accounts.push({
 | 
			
		||||
      name: name || names.filter(name => !currNames.includes(name))[0],
 | 
			
		||||
      xrp: (json.xrp || 0 * 1000000).toString(),
 | 
			
		||||
      address: json.address,
 | 
			
		||||
      secret: json.secret,
 | 
			
		||||
      sequence: 1,
 | 
			
		||||
      hooks: [],
 | 
			
		||||
      isLoading: false,
 | 
			
		||||
      version: '2'
 | 
			
		||||
    })
 | 
			
		||||
    if (!showToast) return;
 | 
			
		||||
    return toast.error(json.error, { id: toastId })
 | 
			
		||||
  }
 | 
			
		||||
  const currNames = state.accounts.map(acc => acc.name)
 | 
			
		||||
  const info = await fetchAccountInfo(json.address, { silent: true })
 | 
			
		||||
  state.accounts.push({
 | 
			
		||||
    name: name || names.filter(name => !currNames.includes(name))[0],
 | 
			
		||||
    xrp: (json.xrp || 0 * 1000000).toString(),
 | 
			
		||||
    address: json.address,
 | 
			
		||||
    secret: json.secret,
 | 
			
		||||
    sequence: info?.Sequence || 1,
 | 
			
		||||
    hooks: [],
 | 
			
		||||
    isLoading: false,
 | 
			
		||||
    version: '2'
 | 
			
		||||
  })
 | 
			
		||||
  if (showToast) {
 | 
			
		||||
    toast.success('New account created', { id: toastId })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// fetch initial faucets
 | 
			
		||||
;(async function fetchFaucets() {
 | 
			
		||||
  if (typeof window !== 'undefined') {
 | 
			
		||||
    if (state.accounts.length === 0) {
 | 
			
		||||
      await addFaucetAccount()
 | 
			
		||||
      // setTimeout(() => {
 | 
			
		||||
      //   addFaucetAccount();
 | 
			
		||||
      // }, 10000);
 | 
			
		||||
  // fetch initial faucets
 | 
			
		||||
  ; (async function fetchFaucets() {
 | 
			
		||||
    if (typeof window !== 'undefined') {
 | 
			
		||||
      if (state.accounts.length === 0) {
 | 
			
		||||
        await addFaucetAccount()
 | 
			
		||||
        // setTimeout(() => {
 | 
			
		||||
        //   addFaucetAccount();
 | 
			
		||||
        // }, 10000);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
})()
 | 
			
		||||
  })()
 | 
			
		||||
 | 
			
		||||
export const addFunds = async (address: string) => {
 | 
			
		||||
  const toastId = toast.loading('Requesting funds')
 | 
			
		||||
 
 | 
			
		||||
@@ -16,17 +16,27 @@ export type HookParameters = {
 | 
			
		||||
  [key: string]: SelectOption
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type Memos = {
 | 
			
		||||
  [key: string]: {
 | 
			
		||||
    type: string
 | 
			
		||||
    format: string
 | 
			
		||||
    data: string
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TransactionState {
 | 
			
		||||
  selectedTransaction: SelectOption | null
 | 
			
		||||
  selectedAccount: SelectOption | null
 | 
			
		||||
  selectedDestAccount: SelectOption | null
 | 
			
		||||
  selectedFlags: SelectOption[] | null
 | 
			
		||||
  hookParameters: HookParameters
 | 
			
		||||
  memos: Memos
 | 
			
		||||
  txIsLoading: boolean
 | 
			
		||||
  txIsDisabled: boolean
 | 
			
		||||
  txFields: TxFields
 | 
			
		||||
  viewType: 'json' | 'ui'
 | 
			
		||||
  editorValue?: string
 | 
			
		||||
  editorIsSaved: boolean
 | 
			
		||||
  estimatedFee?: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -43,6 +53,8 @@ export const defaultTransaction: TransactionState = {
 | 
			
		||||
  selectedDestAccount: null,
 | 
			
		||||
  selectedFlags: null,
 | 
			
		||||
  hookParameters: {},
 | 
			
		||||
  memos: {},
 | 
			
		||||
  editorIsSaved: true,
 | 
			
		||||
  txIsLoading: false,
 | 
			
		||||
  txIsDisabled: false,
 | 
			
		||||
  txFields: {},
 | 
			
		||||
@@ -167,7 +179,7 @@ export const prepareState = (value: string, transactionType?: string) => {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const { Account, TransactionType, Destination, HookParameters, ...rest } = options
 | 
			
		||||
  const { Account, TransactionType, Destination, HookParameters, Memos, ...rest } = options
 | 
			
		||||
  let tx: Partial<TransactionState> = {}
 | 
			
		||||
  const schema = getTxFields(transactionType)
 | 
			
		||||
 | 
			
		||||
@@ -205,6 +217,14 @@ export const prepareState = (value: string, transactionType?: string) => {
 | 
			
		||||
    }, {})
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Memos && Memos instanceof Array) {
 | 
			
		||||
    tx.memos = Memos.reduce<TransactionState["memos"]>((acc, cur, idx) => {
 | 
			
		||||
      const memo = { data: fromHex(cur.Memo?.MemoData || ""), type: fromHex(cur.Memo?.MemoType || ""), format: fromHex(cur.Memo?.MemoFormat || "") }
 | 
			
		||||
      acc[idx] = memo;
 | 
			
		||||
      return acc;
 | 
			
		||||
    }, {})
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (schema.Destination !== undefined) {
 | 
			
		||||
    const dest = state.accounts.find(acc => acc.address === Destination)
 | 
			
		||||
    if (dest) {
 | 
			
		||||
@@ -253,6 +273,7 @@ export const prepareState = (value: string, transactionType?: string) => {
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  tx.txFields = rest
 | 
			
		||||
  tx.editorIsSaved = true;
 | 
			
		||||
 | 
			
		||||
  return tx
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								utils/accountInfo.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								utils/accountInfo.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
import toast from 'react-hot-toast'
 | 
			
		||||
 | 
			
		||||
import { xrplSend } from '../state/actions/xrpl-client'
 | 
			
		||||
 | 
			
		||||
interface AccountInfo {
 | 
			
		||||
    Account: string,
 | 
			
		||||
    Sequence: number,
 | 
			
		||||
    Flags: number,
 | 
			
		||||
    Balance?: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const fetchAccountInfo = async (
 | 
			
		||||
    address: string,
 | 
			
		||||
    opts: { silent?: boolean } = {}
 | 
			
		||||
): Promise<AccountInfo | undefined> => {
 | 
			
		||||
    try {
 | 
			
		||||
        const res = await xrplSend({
 | 
			
		||||
            id: `hooks-builder-req-info-${address}`,
 | 
			
		||||
            command: 'account_info',
 | 
			
		||||
            account: address
 | 
			
		||||
        })
 | 
			
		||||
        return res.account_data;
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        if (!opts.silent) {
 | 
			
		||||
            console.error(err)
 | 
			
		||||
            toast.error('Could not fetch account info!')
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default fetchAccountInfo
 | 
			
		||||
@@ -20,6 +20,13 @@ export type SetHookData = {
 | 
			
		||||
    }
 | 
			
		||||
    $metaData?: any
 | 
			
		||||
  }[]
 | 
			
		||||
  Memos?: {
 | 
			
		||||
    Memo: {
 | 
			
		||||
      MemoType: string,
 | 
			
		||||
      MemoData: string
 | 
			
		||||
      MemoFormat: string
 | 
			
		||||
    }
 | 
			
		||||
  }[]
 | 
			
		||||
  // HookGrants: {
 | 
			
		||||
  //   HookGrant: {
 | 
			
		||||
  //     Authorize: string;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user