Compare commits
18 Commits
feat/amoun
...
fix/hex-va
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc37b1911a | ||
|
|
c348868c89 | ||
|
|
2c3cfebe3a | ||
|
|
6265a9cdbf | ||
|
|
1321b498cf | ||
|
|
801d9778cb | ||
|
|
2cf18ef61c | ||
|
|
4d2dc16ce5 | ||
|
|
9ecf5478e6 | ||
|
|
6d1ef110b7 | ||
|
|
b9edfcd63b | ||
|
|
b653d9a9cb | ||
|
|
da28e0a7d1 | ||
|
|
8a5b83d57f | ||
|
|
025eff6cf2 | ||
|
|
62d521b2cc | ||
|
|
7aafca21df | ||
|
|
80f58e903c |
@@ -3,13 +3,11 @@ import { mauve, mauveDark, purple, purpleDark } from '@radix-ui/colors'
|
|||||||
import { useTheme } from 'next-themes'
|
import { useTheme } from 'next-themes'
|
||||||
import { styled } from '../stitches.config'
|
import { styled } from '../stitches.config'
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
import type { Props } from 'react-select'
|
import type { Props, StylesConfig } from 'react-select'
|
||||||
const SelectInput = dynamic(() => import('react-select'), { ssr: false })
|
const SelectInput = dynamic(() => import('react-select'), { ssr: false })
|
||||||
|
const CreatableSelectInput = dynamic(() => import('react-select/creatable'), { ssr: false })
|
||||||
|
|
||||||
// eslint-disable-next-line react/display-name
|
const getColors = (isDark: boolean) => {
|
||||||
const Select = forwardRef<any, Props>((props, ref) => {
|
|
||||||
const { theme } = useTheme()
|
|
||||||
const isDark = theme === 'dark'
|
|
||||||
const colors: any = {
|
const colors: any = {
|
||||||
// primary: pink.pink9,
|
// primary: pink.pink9,
|
||||||
active: isDark ? purpleDark.purple9 : purple.purple9,
|
active: isDark ? purpleDark.purple9 : purple.purple9,
|
||||||
@@ -30,95 +28,136 @@ const Select = forwardRef<any, Props>((props, ref) => {
|
|||||||
}
|
}
|
||||||
colors.outline = colors.background
|
colors.outline = colors.background
|
||||||
colors.selected = colors.secondary
|
colors.selected = colors.secondary
|
||||||
|
return colors
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStyles = (isDark: boolean) => {
|
||||||
|
const colors = getColors(isDark)
|
||||||
|
const styles: StylesConfig = {
|
||||||
|
container: provided => {
|
||||||
|
return {
|
||||||
|
...provided,
|
||||||
|
position: 'relative',
|
||||||
|
width: '100%'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
singleValue: provided => ({
|
||||||
|
...provided,
|
||||||
|
color: colors.mauve12
|
||||||
|
}),
|
||||||
|
menu: provided => ({
|
||||||
|
...provided,
|
||||||
|
backgroundColor: colors.dropDownBg
|
||||||
|
}),
|
||||||
|
control: (provided, state) => {
|
||||||
|
return {
|
||||||
|
...provided,
|
||||||
|
minHeight: 0,
|
||||||
|
border: '0px',
|
||||||
|
backgroundColor: colors.mauve4,
|
||||||
|
boxShadow: `0 0 0 1px ${state.isFocused ? colors.border : colors.secondary}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
input: provided => {
|
||||||
|
return {
|
||||||
|
...provided,
|
||||||
|
color: '$text'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
multiValue: provided => {
|
||||||
|
return {
|
||||||
|
...provided,
|
||||||
|
backgroundColor: colors.mauve8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
multiValueLabel: provided => {
|
||||||
|
return {
|
||||||
|
...provided,
|
||||||
|
color: colors.mauve12
|
||||||
|
}
|
||||||
|
},
|
||||||
|
multiValueRemove: provided => {
|
||||||
|
return {
|
||||||
|
...provided,
|
||||||
|
':hover': {
|
||||||
|
background: colors.mauve9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
option: (provided, state) => {
|
||||||
|
return {
|
||||||
|
...provided,
|
||||||
|
color: colors.searchText,
|
||||||
|
backgroundColor: state.isFocused ? colors.activeLight : colors.dropDownBg,
|
||||||
|
':hover': {
|
||||||
|
backgroundColor: colors.active,
|
||||||
|
color: '#ffffff'
|
||||||
|
},
|
||||||
|
':selected': {
|
||||||
|
backgroundColor: 'red'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
indicatorSeparator: provided => {
|
||||||
|
return {
|
||||||
|
...provided,
|
||||||
|
backgroundColor: colors.secondary
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dropdownIndicator: (provided, state) => {
|
||||||
|
return {
|
||||||
|
...provided,
|
||||||
|
padding: 6,
|
||||||
|
color: state.isFocused ? colors.border : colors.secondary,
|
||||||
|
':hover': {
|
||||||
|
color: colors.border
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearIndicator: provided => {
|
||||||
|
return {
|
||||||
|
...provided,
|
||||||
|
padding: 6,
|
||||||
|
color: colors.secondary,
|
||||||
|
':hover': {
|
||||||
|
color: colors.border
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return styles
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/display-name
|
||||||
|
const Select = forwardRef<any, Props>((props, ref) => {
|
||||||
|
const { theme } = useTheme()
|
||||||
|
const isDark = theme === 'dark'
|
||||||
|
const styles = getStyles(isDark)
|
||||||
return (
|
return (
|
||||||
<SelectInput
|
<SelectInput
|
||||||
ref={ref}
|
ref={ref}
|
||||||
menuPosition={props.menuPosition || 'fixed'}
|
menuPosition={props.menuPosition || 'fixed'}
|
||||||
styles={{
|
styles={styles}
|
||||||
container: provided => {
|
{...props}
|
||||||
return {
|
/>
|
||||||
...provided,
|
)
|
||||||
position: 'relative',
|
})
|
||||||
width: '100%',
|
|
||||||
}
|
// eslint-disable-next-line react/display-name
|
||||||
},
|
const Creatable = forwardRef<any, Props>((props, ref) => {
|
||||||
singleValue: provided => ({
|
const { theme } = useTheme()
|
||||||
...provided,
|
const isDark = theme === 'dark'
|
||||||
color: colors.mauve12
|
const styles = getStyles(isDark)
|
||||||
}),
|
return (
|
||||||
menu: provided => ({
|
<CreatableSelectInput
|
||||||
...provided,
|
ref={ref}
|
||||||
backgroundColor: colors.dropDownBg
|
formatCreateLabel={label => `Enter "${label}"`}
|
||||||
}),
|
menuPosition={props.menuPosition || 'fixed'}
|
||||||
control: (provided, state) => {
|
styles={styles}
|
||||||
return {
|
|
||||||
...provided,
|
|
||||||
minHeight: 0,
|
|
||||||
border: '0px',
|
|
||||||
backgroundColor: colors.mauve4,
|
|
||||||
boxShadow: `0 0 0 1px ${state.isFocused ? colors.border : colors.secondary}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
input: provided => {
|
|
||||||
return {
|
|
||||||
...provided,
|
|
||||||
color: '$text'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
multiValue: provided => {
|
|
||||||
return {
|
|
||||||
...provided,
|
|
||||||
backgroundColor: colors.mauve8
|
|
||||||
}
|
|
||||||
},
|
|
||||||
multiValueLabel: provided => {
|
|
||||||
return {
|
|
||||||
...provided,
|
|
||||||
color: colors.mauve12
|
|
||||||
}
|
|
||||||
},
|
|
||||||
multiValueRemove: provided => {
|
|
||||||
return {
|
|
||||||
...provided,
|
|
||||||
':hover': {
|
|
||||||
background: colors.mauve9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
option: (provided, state) => {
|
|
||||||
return {
|
|
||||||
...provided,
|
|
||||||
color: colors.searchText,
|
|
||||||
backgroundColor: state.isFocused ? colors.activeLight : colors.dropDownBg,
|
|
||||||
':hover': {
|
|
||||||
backgroundColor: colors.active,
|
|
||||||
color: '#ffffff'
|
|
||||||
},
|
|
||||||
':selected': {
|
|
||||||
backgroundColor: 'red'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
indicatorSeparator: provided => {
|
|
||||||
return {
|
|
||||||
...provided,
|
|
||||||
backgroundColor: colors.secondary
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dropdownIndicator: (provided, state) => {
|
|
||||||
return {
|
|
||||||
...provided,
|
|
||||||
padding: 6,
|
|
||||||
color: state.isFocused ? colors.border : colors.secondary,
|
|
||||||
':hover': {
|
|
||||||
color: colors.border,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export default styled(Select, {})
|
export default styled(Select, {})
|
||||||
|
export const CreatableSelect = styled(Creatable, {})
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
|
|||||||
(state: Partial<TransactionState> = txState) => {
|
(state: Partial<TransactionState> = txState) => {
|
||||||
const {
|
const {
|
||||||
selectedTransaction,
|
selectedTransaction,
|
||||||
selectedDestAccount,
|
|
||||||
selectedAccount,
|
selectedAccount,
|
||||||
txFields,
|
txFields,
|
||||||
selectedFlags,
|
selectedFlags,
|
||||||
@@ -52,20 +51,19 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
|
|||||||
} = state
|
} = state
|
||||||
|
|
||||||
const TransactionType = selectedTransaction?.value || null
|
const TransactionType = selectedTransaction?.value || null
|
||||||
const Destination = selectedDestAccount?.value || txFields?.Destination
|
|
||||||
const Account = selectedAccount?.value || null
|
const Account = selectedAccount?.value || null
|
||||||
const Flags = combineFlags(selectedFlags?.map(flag => flag.value)) || txFields?.Flags
|
const Flags = combineFlags(selectedFlags?.map(flag => flag.value)) || txFields?.Flags
|
||||||
const HookParameters = Object.entries(hookParameters || {}).reduce<
|
const HookParameters = Object.entries(hookParameters || {}).reduce<
|
||||||
SetHookData['HookParameters']
|
SetHookData['HookParameters']
|
||||||
>((acc, [_, { label, value }]) => {
|
>((acc, [_, { label, value }]) => {
|
||||||
return acc.concat({
|
return acc.concat({
|
||||||
HookParameter: { HookParameterName: toHex(label), HookParameterValue: toHex(value) }
|
HookParameter: { HookParameterName: toHex(label), HookParameterValue: value }
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
const Memos = memos
|
const Memos = memos
|
||||||
? Object.entries(memos).reduce<SetHookData['Memos']>((acc, [_, { format, data, type }]) => {
|
? Object.entries(memos).reduce<SetHookData['Memos']>((acc, [_, { format, data, type }]) => {
|
||||||
return acc?.concat({
|
return acc?.concat({
|
||||||
Memo: { MemoData: toHex(data), MemoFormat: toHex(format), MemoType: toHex(type) }
|
Memo: { MemoData: data, MemoFormat: toHex(format), MemoType: toHex(type) }
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
: undefined
|
: undefined
|
||||||
@@ -75,7 +73,6 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
|
|||||||
HookParameters,
|
HookParameters,
|
||||||
Flags,
|
Flags,
|
||||||
TransactionType,
|
TransactionType,
|
||||||
Destination,
|
|
||||||
Account,
|
Account,
|
||||||
Memos
|
Memos
|
||||||
})
|
})
|
||||||
@@ -128,11 +125,12 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
|
|||||||
throw Error('Account must be selected from imported accounts!')
|
throw Error('Account must be selected from imported accounts!')
|
||||||
}
|
}
|
||||||
const options = prepareOptions(st)
|
const options = prepareOptions(st)
|
||||||
|
// delete unnecessary fields
|
||||||
const fields = getTxFields(options.TransactionType)
|
Object.keys(options).forEach(field => {
|
||||||
if (fields.Destination && !options.Destination) {
|
if (!options[field]) {
|
||||||
throw Error('Destination account is required!')
|
delete options[field]
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
await sendTransaction(account, options, { logPrefix })
|
await sendTransaction(account, options, { logPrefix })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -167,13 +165,6 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
|
|||||||
selectedTransaction: transactionType
|
selectedTransaction: transactionType
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fields.Destination !== undefined) {
|
|
||||||
nwState.selectedDestAccount = null
|
|
||||||
fields.Destination = ''
|
|
||||||
} else {
|
|
||||||
fields.Destination = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transactionType?.value && transactionFlags[transactionType?.value] && fields.Flags) {
|
if (transactionType?.value && transactionFlags[transactionType?.value] && fields.Flags) {
|
||||||
nwState.selectedFlags = extractFlags(transactionType.value, fields.Flags)
|
nwState.selectedFlags = extractFlags(transactionType.value, fields.Flags)
|
||||||
fields.Flags = undefined
|
fields.Flags = undefined
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { FC, ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
|
import { FC, ReactNode, useCallback, useEffect, useState } from 'react'
|
||||||
import Container from '../Container'
|
import Container from '../Container'
|
||||||
import Flex from '../Flex'
|
import Flex from '../Flex'
|
||||||
import Input from '../Input'
|
import Input from '../Input'
|
||||||
import Select from '../Select'
|
import Select, { CreatableSelect } from '../Select'
|
||||||
import Text from '../Text'
|
import Text from '../Text'
|
||||||
import {
|
import {
|
||||||
SelectOption,
|
SelectOption,
|
||||||
TransactionState,
|
TransactionState,
|
||||||
transactionsOptions,
|
transactionsOptions,
|
||||||
TxFields,
|
TxFields,
|
||||||
getTxFields,
|
|
||||||
defaultTransactionType
|
defaultTransactionType
|
||||||
} from '../../state/transactions'
|
} from '../../state/transactions'
|
||||||
import { useSnapshot } from 'valtio'
|
import { useSnapshot } from 'valtio'
|
||||||
@@ -20,7 +19,7 @@ import Textarea from '../Textarea'
|
|||||||
import { getFlags } from '../../state/constants/flags'
|
import { getFlags } from '../../state/constants/flags'
|
||||||
import { Plus, Trash } from 'phosphor-react'
|
import { Plus, Trash } from 'phosphor-react'
|
||||||
import AccountSequence from '../Sequence'
|
import AccountSequence from '../Sequence'
|
||||||
import { typeIs } from '../../utils/helpers'
|
import { capitalize, typeIs } from '../../utils/helpers'
|
||||||
|
|
||||||
interface UIProps {
|
interface UIProps {
|
||||||
setState: (pTx?: Partial<TransactionState> | undefined) => TransactionState | undefined
|
setState: (pTx?: Partial<TransactionState> | undefined) => TransactionState | undefined
|
||||||
@@ -38,28 +37,14 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
switchToJson
|
switchToJson
|
||||||
}) => {
|
}) => {
|
||||||
const { accounts } = useSnapshot(state)
|
const { accounts } = useSnapshot(state)
|
||||||
const {
|
const { selectedAccount, selectedTransaction, txFields, selectedFlags, hookParameters, memos } =
|
||||||
selectedAccount,
|
txState
|
||||||
selectedDestAccount,
|
|
||||||
selectedTransaction,
|
|
||||||
txFields,
|
|
||||||
selectedFlags,
|
|
||||||
hookParameters,
|
|
||||||
memos
|
|
||||||
} = txState
|
|
||||||
|
|
||||||
const accountOptions: SelectOption[] = accounts.map(acc => ({
|
const accountOptions: SelectOption[] = accounts.map(acc => ({
|
||||||
label: acc.name,
|
label: acc.name,
|
||||||
value: acc.address
|
value: acc.address
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const destAccountOptions: SelectOption[] = accounts
|
|
||||||
.map(acc => ({
|
|
||||||
label: acc.name,
|
|
||||||
value: acc.address
|
|
||||||
}))
|
|
||||||
.filter(acc => acc.value !== selectedAccount?.value)
|
|
||||||
|
|
||||||
const flagsOptions: SelectOption[] = Object.entries(
|
const flagsOptions: SelectOption[] = Object.entries(
|
||||||
getFlags(selectedTransaction?.value) || {}
|
getFlags(selectedTransaction?.value) || {}
|
||||||
).map(([label, value]) => ({
|
).map(([label, value]) => ({
|
||||||
@@ -136,15 +121,7 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
}
|
}
|
||||||
}, [handleChangeTxType, selectedTransaction?.value])
|
}, [handleChangeTxType, selectedTransaction?.value])
|
||||||
|
|
||||||
const fields = useMemo(
|
|
||||||
() => getTxFields(selectedTransaction?.value),
|
|
||||||
[selectedTransaction?.value]
|
|
||||||
)
|
|
||||||
|
|
||||||
const richFields = ['TransactionType', 'Account', 'HookParameters', 'Memos']
|
const richFields = ['TransactionType', 'Account', 'HookParameters', 'Memos']
|
||||||
if (fields.Destination !== undefined) {
|
|
||||||
richFields.push('Destination')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flagsOptions.length) {
|
if (flagsOptions.length) {
|
||||||
richFields.push('Flags')
|
richFields.push('Flags')
|
||||||
@@ -192,18 +169,6 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
<TxField label="Sequence">
|
<TxField label="Sequence">
|
||||||
<AccountSequence address={selectedAccount?.value} />
|
<AccountSequence address={selectedAccount?.value} />
|
||||||
</TxField>
|
</TxField>
|
||||||
{richFields.includes('Destination') && (
|
|
||||||
<TxField label="Destination account">
|
|
||||||
<Select
|
|
||||||
instanceId="to-account"
|
|
||||||
placeholder="Select the destination account"
|
|
||||||
options={destAccountOptions}
|
|
||||||
value={selectedDestAccount}
|
|
||||||
isClearable
|
|
||||||
onChange={(acc: any) => setState({ selectedDestAccount: acc })}
|
|
||||||
/>
|
|
||||||
</TxField>
|
|
||||||
)}
|
|
||||||
{richFields.includes('Flags') && (
|
{richFields.includes('Flags') && (
|
||||||
<TxField label="Flags">
|
<TxField label="Flags">
|
||||||
<Select
|
<Select
|
||||||
@@ -235,6 +200,7 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
value = _value?.toString()
|
value = _value?.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isAccount = typeIs(_value, 'object') && _value.$type === 'account'
|
||||||
const isXrpAmount = typeIs(_value, 'object') && _value.$type === 'amount.xrp'
|
const isXrpAmount = typeIs(_value, 'object') && _value.$type === 'amount.xrp'
|
||||||
const isTokenAmount = typeIs(_value, 'object') && _value.$type === 'amount.token'
|
const isTokenAmount = typeIs(_value, 'object') && _value.$type === 'amount.token'
|
||||||
const isJson = typeof _value === 'object' && _value.$type === 'json'
|
const isJson = typeof _value === 'object' && _value.$type === 'json'
|
||||||
@@ -255,8 +221,14 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
<TxField key={field} label={field}>
|
<TxField key={field} label={field}>
|
||||||
<Flex fluid css={{ alignItems: 'center' }}>
|
<Flex fluid css={{ alignItems: 'center' }}>
|
||||||
{isTokenAmount ? (
|
{isTokenAmount ? (
|
||||||
<Flex fluid row align="center" justify="space-between">
|
<Flex
|
||||||
<Input
|
fluid
|
||||||
|
row
|
||||||
|
align="center"
|
||||||
|
justify="space-between"
|
||||||
|
css={{ position: 'relative' }}
|
||||||
|
>
|
||||||
|
{/* <Input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Issuer"
|
placeholder="Issuer"
|
||||||
value={tokenAmount.issuer}
|
value={tokenAmount.issuer}
|
||||||
@@ -266,9 +238,8 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
issuer: e.target.value
|
issuer: e.target.value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/> */}
|
||||||
<Input
|
<Input
|
||||||
css={{ mx: '$1' }}
|
|
||||||
type="text"
|
type="text"
|
||||||
value={tokenAmount.currency}
|
value={tokenAmount.currency}
|
||||||
placeholder="Currency"
|
placeholder="Currency"
|
||||||
@@ -280,6 +251,7 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
|
css={{ mx: '$1' }}
|
||||||
type="number"
|
type="number"
|
||||||
value={tokenAmount.value}
|
value={tokenAmount.value}
|
||||||
placeholder="Value"
|
placeholder="Value"
|
||||||
@@ -290,6 +262,19 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Box css={{ width: '50%' }}>
|
||||||
|
<CreatableAccount
|
||||||
|
value={tokenAmount.issuer}
|
||||||
|
field={'Issuer' as any}
|
||||||
|
placeholder="Issuer"
|
||||||
|
setField={(_, value = '') => {
|
||||||
|
setRawField(field, 'amount.token', {
|
||||||
|
...tokenAmount,
|
||||||
|
issuer: value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
) : (
|
) : (
|
||||||
<Input
|
<Input
|
||||||
@@ -323,6 +308,13 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
</TxField>
|
</TxField>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (isAccount) {
|
||||||
|
return (
|
||||||
|
<TxField key={field} label={field}>
|
||||||
|
<CreatableAccount value={value} field={field} setField={handleSetField} />
|
||||||
|
</TxField>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<TxField key={field} label={field}>
|
<TxField key={field} label={field}>
|
||||||
{isJson ? (
|
{isJson ? (
|
||||||
@@ -414,7 +406,7 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
css={{ mx: '$2' }}
|
css={{ mx: '$2' }}
|
||||||
placeholder="Value"
|
placeholder="Value (hex-quoted)"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
setState({
|
setState({
|
||||||
@@ -477,7 +469,7 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Data"
|
placeholder="Data (hex-quoted)"
|
||||||
css={{ mx: '$2' }}
|
css={{ mx: '$2' }}
|
||||||
value={memo.data}
|
value={memo.data}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
@@ -535,6 +527,35 @@ export const TxUI: FC<UIProps> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const CreatableAccount: FC<{
|
||||||
|
value: string | undefined
|
||||||
|
field: keyof TxFields
|
||||||
|
placeholder?: string
|
||||||
|
setField: (field: keyof TxFields, value: string, opFields?: TxFields) => void
|
||||||
|
}> = ({ value, field, setField, placeholder }) => {
|
||||||
|
const { accounts } = useSnapshot(state)
|
||||||
|
const accountOptions: SelectOption[] = accounts.map(acc => ({
|
||||||
|
label: acc.name,
|
||||||
|
value: acc.address
|
||||||
|
}))
|
||||||
|
const label = accountOptions.find(a => a.value === value)?.label || value
|
||||||
|
const val = {
|
||||||
|
value,
|
||||||
|
label
|
||||||
|
}
|
||||||
|
placeholder = placeholder || `${capitalize(field)} account`
|
||||||
|
return (
|
||||||
|
<CreatableSelect
|
||||||
|
isClearable
|
||||||
|
instanceId={field}
|
||||||
|
placeholder={placeholder}
|
||||||
|
options={accountOptions}
|
||||||
|
value={value ? val : undefined}
|
||||||
|
onChange={(acc: any) => setField(field, acc?.value)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export const TxField: FC<{ label: string; children: ReactNode; multiLine?: boolean }> = ({
|
export const TxField: FC<{ label: string; children: ReactNode; multiLine?: boolean }> = ({
|
||||||
label,
|
label,
|
||||||
children,
|
children,
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
{
|
{
|
||||||
"TransactionType": "AccountDelete",
|
"TransactionType": "AccountDelete",
|
||||||
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
|
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
|
||||||
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
|
"Destination": {
|
||||||
|
"$type": "account",
|
||||||
|
"$value": ""
|
||||||
|
},
|
||||||
"DestinationTag": 13,
|
"DestinationTag": 13,
|
||||||
"Fee": "2000000",
|
"Fee": "2000000",
|
||||||
"Sequence": 2470665,
|
"Sequence": 2470665,
|
||||||
@@ -40,7 +43,10 @@
|
|||||||
{
|
{
|
||||||
"TransactionType": "CheckCreate",
|
"TransactionType": "CheckCreate",
|
||||||
"Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
|
"Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
|
||||||
"Destination": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
|
"Destination": {
|
||||||
|
"$type": "account",
|
||||||
|
"$value": ""
|
||||||
|
},
|
||||||
"SendMax": "100000000",
|
"SendMax": "100000000",
|
||||||
"Expiration": 570113521,
|
"Expiration": 570113521,
|
||||||
"InvoiceID": "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B",
|
"InvoiceID": "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B",
|
||||||
@@ -58,7 +64,10 @@
|
|||||||
{
|
{
|
||||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"TransactionType": "EscrowCancel",
|
"TransactionType": "EscrowCancel",
|
||||||
"Owner": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Owner": {
|
||||||
|
"$type": "account",
|
||||||
|
"$value": ""
|
||||||
|
},
|
||||||
"OfferSequence": 7,
|
"OfferSequence": 7,
|
||||||
"Fee": "10"
|
"Fee": "10"
|
||||||
},
|
},
|
||||||
@@ -69,7 +78,10 @@
|
|||||||
"$value": "100",
|
"$value": "100",
|
||||||
"$type": "amount.xrp"
|
"$type": "amount.xrp"
|
||||||
},
|
},
|
||||||
"Destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
"Destination": {
|
||||||
|
"$type": "account",
|
||||||
|
"$value": ""
|
||||||
|
},
|
||||||
"CancelAfter": 533257958,
|
"CancelAfter": 533257958,
|
||||||
"FinishAfter": 533171558,
|
"FinishAfter": 533171558,
|
||||||
"Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
|
"Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
|
||||||
@@ -80,7 +92,10 @@
|
|||||||
{
|
{
|
||||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"TransactionType": "EscrowFinish",
|
"TransactionType": "EscrowFinish",
|
||||||
"Owner": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Owner": {
|
||||||
|
"$type": "account",
|
||||||
|
"$value": ""
|
||||||
|
},
|
||||||
"OfferSequence": 7,
|
"OfferSequence": 7,
|
||||||
"Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
|
"Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
|
||||||
"Fulfillment": "A0028000",
|
"Fulfillment": "A0028000",
|
||||||
@@ -127,7 +142,14 @@
|
|||||||
"$type": "amount.xrp"
|
"$type": "amount.xrp"
|
||||||
},
|
},
|
||||||
"Flags": "1",
|
"Flags": "1",
|
||||||
"Destination": "",
|
"Destination": {
|
||||||
|
"$type": "account",
|
||||||
|
"$value": ""
|
||||||
|
},
|
||||||
|
"Owner": {
|
||||||
|
"$type": "account",
|
||||||
|
"$value": ""
|
||||||
|
},
|
||||||
"Fee": "10"
|
"Fee": "10"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -162,7 +184,10 @@
|
|||||||
{
|
{
|
||||||
"TransactionType": "Payment",
|
"TransactionType": "Payment",
|
||||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"Destination": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
"Destination": {
|
||||||
|
"$type": "account",
|
||||||
|
"$value": ""
|
||||||
|
},
|
||||||
"Amount": {
|
"Amount": {
|
||||||
"$value": "100",
|
"$value": "100",
|
||||||
"$type": "amount.xrp"
|
"$type": "amount.xrp"
|
||||||
@@ -178,7 +203,10 @@
|
|||||||
"$value": "100",
|
"$value": "100",
|
||||||
"$type": "amount.xrp"
|
"$type": "amount.xrp"
|
||||||
},
|
},
|
||||||
"Destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
"Destination": {
|
||||||
|
"$type": "account",
|
||||||
|
"$value": ""
|
||||||
|
},
|
||||||
"SettleDelay": 86400,
|
"SettleDelay": 86400,
|
||||||
"PublicKey": "32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A",
|
"PublicKey": "32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A",
|
||||||
"CancelAfter": 533171558,
|
"CancelAfter": 533171558,
|
||||||
@@ -259,6 +287,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"TransactionType": "Invoke",
|
"TransactionType": "Invoke",
|
||||||
|
"Destination": {
|
||||||
|
"$type": "account",
|
||||||
|
"$value": ""
|
||||||
|
},
|
||||||
"Fee": "12"
|
"Fee": "12"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,11 +14,4 @@ export const deleteAccount = (addr?: string) => {
|
|||||||
if (!acc) return
|
if (!acc) return
|
||||||
acc.label = acc.value
|
acc.label = acc.value
|
||||||
})
|
})
|
||||||
transactionsState.transactions
|
|
||||||
.filter(t => t.state.selectedDestAccount?.value === addr)
|
|
||||||
.forEach(t => {
|
|
||||||
const acc = t.state.selectedDestAccount
|
|
||||||
if (!acc) return
|
|
||||||
acc.label = acc.value
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ interface TransactionOptions {
|
|||||||
TransactionType: string
|
TransactionType: string
|
||||||
Account?: string
|
Account?: string
|
||||||
Fee?: string
|
Fee?: string
|
||||||
Destination?: string
|
|
||||||
[index: string]: any
|
[index: string]: any
|
||||||
}
|
}
|
||||||
interface OtherOptions {
|
interface OtherOptions {
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ export type Memos = {
|
|||||||
export interface TransactionState {
|
export interface TransactionState {
|
||||||
selectedTransaction: SelectOption | null
|
selectedTransaction: SelectOption | null
|
||||||
selectedAccount: SelectOption | null
|
selectedAccount: SelectOption | null
|
||||||
selectedDestAccount: SelectOption | null
|
|
||||||
selectedFlags: SelectOption[] | null
|
selectedFlags: SelectOption[] | null
|
||||||
hookParameters: HookParameters
|
hookParameters: HookParameters
|
||||||
memos: Memos
|
memos: Memos
|
||||||
@@ -51,7 +50,6 @@ export type TxFields = Omit<
|
|||||||
export const defaultTransaction: TransactionState = {
|
export const defaultTransaction: TransactionState = {
|
||||||
selectedTransaction: null,
|
selectedTransaction: null,
|
||||||
selectedAccount: null,
|
selectedAccount: null,
|
||||||
selectedDestAccount: null,
|
|
||||||
selectedFlags: null,
|
selectedFlags: null,
|
||||||
hookParameters: {},
|
hookParameters: {},
|
||||||
memos: {},
|
memos: {},
|
||||||
@@ -131,7 +129,6 @@ export const modifyTxState = (
|
|||||||
return tx.state
|
return tx.state
|
||||||
}
|
}
|
||||||
|
|
||||||
// state to tx options
|
|
||||||
export const prepareTransaction = (data: any) => {
|
export const prepareTransaction = (data: any) => {
|
||||||
let options = { ...data }
|
let options = { ...data }
|
||||||
|
|
||||||
@@ -143,10 +140,9 @@ export const prepareTransaction = (data: any) => {
|
|||||||
if (_value.$value) {
|
if (_value.$value) {
|
||||||
options[field] = (+(_value as any).$value * 1000000 + '')
|
options[field] = (+(_value as any).$value * 1000000 + '')
|
||||||
} else {
|
} else {
|
||||||
options[field] = undefined
|
options[field] = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// amount.token
|
// amount.token
|
||||||
if (_value.$type === 'amount.token') {
|
if (_value.$type === 'amount.token') {
|
||||||
if (typeIs(_value.$value, 'string')) {
|
if (typeIs(_value.$value, 'string')) {
|
||||||
@@ -157,7 +153,10 @@ export const prepareTransaction = (data: any) => {
|
|||||||
options[field] = undefined
|
options[field] = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// account
|
||||||
|
if (_value.$type === 'account') {
|
||||||
|
options[field] = (_value.$value as any)?.toString() || ""
|
||||||
|
}
|
||||||
// json
|
// json
|
||||||
if (_value.$type === 'json') {
|
if (_value.$type === 'json') {
|
||||||
const val = _value.$value;
|
const val = _value.$value;
|
||||||
@@ -172,17 +171,9 @@ export const prepareTransaction = (data: any) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// delete unnecessary fields
|
|
||||||
Object.keys(options).forEach(field => {
|
|
||||||
if (!options[field]) {
|
|
||||||
delete options[field]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
// editor value to state
|
|
||||||
export const prepareState = (value: string, transactionType?: string) => {
|
export const prepareState = (value: string, transactionType?: string) => {
|
||||||
const options = parseJSON(value)
|
const options = parseJSON(value)
|
||||||
if (!options) {
|
if (!options) {
|
||||||
@@ -192,7 +183,7 @@ export const prepareState = (value: string, transactionType?: string) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const { Account, TransactionType, Destination, HookParameters, Memos, ...rest } = options
|
const { Account, TransactionType, HookParameters, Memos, ...rest } = options
|
||||||
let tx: Partial<TransactionState> = {}
|
let tx: Partial<TransactionState> = {}
|
||||||
const schema = getTxFields(transactionType)
|
const schema = getTxFields(transactionType)
|
||||||
|
|
||||||
@@ -224,7 +215,7 @@ export const prepareState = (value: string, transactionType?: string) => {
|
|||||||
|
|
||||||
if (HookParameters && HookParameters instanceof Array) {
|
if (HookParameters && HookParameters instanceof Array) {
|
||||||
tx.hookParameters = HookParameters.reduce<TransactionState["hookParameters"]>((acc, cur, idx) => {
|
tx.hookParameters = HookParameters.reduce<TransactionState["hookParameters"]>((acc, cur, idx) => {
|
||||||
const param = { label: fromHex(cur.HookParameter?.HookParameterName || ""), value: fromHex(cur.HookParameter?.HookParameterValue || "") }
|
const param = { label: fromHex(cur.HookParameter?.HookParameterName || ""), value: cur.HookParameter?.HookParameterValue || "" }
|
||||||
acc[idx] = param;
|
acc[idx] = param;
|
||||||
return acc;
|
return acc;
|
||||||
}, {})
|
}, {})
|
||||||
@@ -232,30 +223,12 @@ export const prepareState = (value: string, transactionType?: string) => {
|
|||||||
|
|
||||||
if (Memos && Memos instanceof Array) {
|
if (Memos && Memos instanceof Array) {
|
||||||
tx.memos = Memos.reduce<TransactionState["memos"]>((acc, cur, idx) => {
|
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 || "") }
|
const memo = { data: cur.Memo?.MemoData || "", type: fromHex(cur.Memo?.MemoType || ""), format: fromHex(cur.Memo?.MemoFormat || "") }
|
||||||
acc[idx] = memo;
|
acc[idx] = memo;
|
||||||
return acc;
|
return acc;
|
||||||
}, {})
|
}, {})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.Destination !== undefined) {
|
|
||||||
const dest = state.accounts.find(acc => acc.address === Destination)
|
|
||||||
if (dest) {
|
|
||||||
tx.selectedDestAccount = {
|
|
||||||
label: dest.name,
|
|
||||||
value: dest.address
|
|
||||||
}
|
|
||||||
} else if (Destination) {
|
|
||||||
tx.selectedDestAccount = {
|
|
||||||
label: Destination,
|
|
||||||
value: Destination
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tx.selectedDestAccount = null
|
|
||||||
}
|
|
||||||
} else if (Destination) {
|
|
||||||
rest.Destination = Destination
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getFlags(TransactionType) && rest.Flags) {
|
if (getFlags(TransactionType) && rest.Flags) {
|
||||||
const flags = extractFlags(TransactionType, rest.Flags)
|
const flags = extractFlags(TransactionType, rest.Flags)
|
||||||
@@ -271,19 +244,27 @@ export const prepareState = (value: string, transactionType?: string) => {
|
|||||||
const isAmount = schemaVal &&
|
const isAmount = schemaVal &&
|
||||||
typeIs(schemaVal, "object") &&
|
typeIs(schemaVal, "object") &&
|
||||||
schemaVal.$type.startsWith('amount.');
|
schemaVal.$type.startsWith('amount.');
|
||||||
|
const isAccount = schemaVal &&
|
||||||
|
typeIs(schemaVal, "object") &&
|
||||||
|
schemaVal.$type.startsWith("account");
|
||||||
|
|
||||||
if (isAmount && ["number", "string"].includes(typeof value)) {
|
if (isAmount && ["number", "string"].includes(typeof value)) {
|
||||||
rest[field] = {
|
rest[field] = {
|
||||||
$type: 'amount.xrp', // Maybe have $type map or something
|
$type: 'amount.xrp', // TODO narrow typed $type.
|
||||||
$value: +value / 1000000 // ! maybe use bigint?
|
$value: +value / 1000000 // ! maybe use bigint?
|
||||||
}
|
}
|
||||||
}
|
} else if (isAmount && typeof value === 'object') {
|
||||||
else if (isAmount && typeof value === 'object') {
|
|
||||||
rest[field] = {
|
rest[field] = {
|
||||||
$type: 'amount.token',
|
$type: 'amount.token',
|
||||||
$value: value
|
$value: value
|
||||||
}
|
}
|
||||||
} else if (typeof value === 'object') {
|
} else if (isAccount) {
|
||||||
|
rest[field] = {
|
||||||
|
$type: "account",
|
||||||
|
$value: value?.toString() || ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (typeof value === 'object') {
|
||||||
rest[field] = {
|
rest[field] = {
|
||||||
$type: 'json',
|
$type: 'json',
|
||||||
$value: value
|
$value: value
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const tts = {
|
|||||||
export type TTS = typeof tts
|
export type TTS = typeof tts
|
||||||
|
|
||||||
const calculateHookOn = (arr: (keyof TTS)[]) => {
|
const calculateHookOn = (arr: (keyof TTS)[]) => {
|
||||||
let s = '0x3e3ff5bf'
|
let s = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff'
|
||||||
arr.forEach(n => {
|
arr.forEach(n => {
|
||||||
let v = BigInt(s)
|
let v = BigInt(s)
|
||||||
v ^= BigInt(1) << BigInt(tts[n])
|
v ^= BigInt(1) << BigInt(tts[n])
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ export const getInvokeOptions = (content?: string) => {
|
|||||||
export function toHex(str: string) {
|
export function toHex(str: string) {
|
||||||
var result = ''
|
var result = ''
|
||||||
for (var i = 0; i < str.length; i++) {
|
for (var i = 0; i < str.length; i++) {
|
||||||
result += str.charCodeAt(i).toString(16)
|
const hex = str.charCodeAt(i).toString(16)
|
||||||
|
result += hex.padStart(2, '0')
|
||||||
}
|
}
|
||||||
return result.toUpperCase()
|
return result.toUpperCase()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user