diff --git a/src/components/Earn.jsx b/src/components/Earn.tsx
similarity index 50%
rename from src/components/Earn.jsx
rename to src/components/Earn.tsx
index c1c2120d..857980a9 100644
--- a/src/components/Earn.jsx
+++ b/src/components/Earn.tsx
@@ -1,11 +1,11 @@
-import { useEffect, useMemo, useState } from 'react'
-import { Formik } from 'formik'
+import { useCallback, useEffect, useMemo, useState } from 'react'
+import { Formik, FormikErrors } from 'formik'
import * as rb from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import { useSettings } from '../context/SettingsContext'
-import { useCurrentWalletInfo, useReloadCurrentWalletInfo } from '../context/WalletContext'
-import { useServiceInfo, useReloadServiceInfo } from '../context/ServiceInfoContext'
-import { factorToPercentage, percentageToFactor } from '../utils'
+import { CurrentWallet, useCurrentWalletInfo, useReloadCurrentWalletInfo } from '../context/WalletContext'
+import { useServiceInfo, useReloadServiceInfo, Offer } from '../context/ServiceInfoContext'
+import { factorToPercentage, isValidNumber, percentageToFactor } from '../utils'
import * as Api from '../libs/JmWalletApi'
import * as fb from './fb/utils'
import Sprite from './Sprite'
@@ -19,6 +19,7 @@ import { OrderbookOverlay } from './Orderbook'
import Balance from './Balance'
import styles from './Earn.module.css'
import Accordion from './Accordion'
+import { TFunction } from 'i18next'
// In order to prevent state mismatch, the 'maker stop' response is delayed shortly.
// Even though the API response suggests that the maker has started or stopped immediately, it seems that this is not always the case.
@@ -34,10 +35,10 @@ const OFFERTYPE_REL = 'sw0reloffer'
const OFFERTYPE_ABS = 'sw0absoffer'
// can be any of ['sw0reloffer', 'swreloffer', 'reloffer']
-const isRelativeOffer = (offertype) => offertype.includes('reloffer')
+const isRelativeOffer = (offertype: string) => offertype.includes('reloffer')
// can be any of ['sw0absoffer', 'swabsoffer', 'absoffer']
-const isAbsoluteOffer = (offertype) => offertype.includes('absoffer')
+const isAbsoluteOffer = (offertype: string) => offertype.includes('absoffer')
const FORM_INPUT_LOCAL_STORAGE_KEYS = {
offertype: 'jm-offertype',
@@ -46,48 +47,70 @@ const FORM_INPUT_LOCAL_STORAGE_KEYS = {
minsize: 'jm-minsize',
}
-const FORM_INPUT_DEFAULT_VALUES = {
+export interface EarnFormValues {
+ offertype: Api.OfferType
+ feeRel: number
+ feeAbs: number
+ minsize: number
+}
+
+const FORM_INPUT_DEFAULT_VALUES: EarnFormValues = {
offertype: OFFERTYPE_REL,
feeRel: 0.000_3,
feeAbs: 250,
minsize: 100_000,
}
-const persistFormValues = (values) => {
+const persistFormValues = (values: EarnFormValues) => {
window.localStorage.setItem(FORM_INPUT_LOCAL_STORAGE_KEYS.offertype, values.offertype)
- window.localStorage.setItem(FORM_INPUT_LOCAL_STORAGE_KEYS.minsize, values.minsize)
+ window.localStorage.setItem(FORM_INPUT_LOCAL_STORAGE_KEYS.minsize, String(values.minsize))
if (isRelativeOffer(values.offertype)) {
- window.localStorage.setItem(FORM_INPUT_LOCAL_STORAGE_KEYS.feeRel, values.feeRel)
+ window.localStorage.setItem(FORM_INPUT_LOCAL_STORAGE_KEYS.feeRel, String(values.feeRel))
}
if (isAbsoluteOffer(values.offertype)) {
- window.localStorage.setItem(FORM_INPUT_LOCAL_STORAGE_KEYS.feeAbs, values.feeAbs)
+ window.localStorage.setItem(FORM_INPUT_LOCAL_STORAGE_KEYS.feeAbs, String(values.feeAbs))
}
}
-const initialFormValues = () => ({
- offertype:
- window.localStorage.getItem(FORM_INPUT_LOCAL_STORAGE_KEYS.offertype) || FORM_INPUT_DEFAULT_VALUES.offertype,
- feeRel:
- parseFloat(window.localStorage.getItem(FORM_INPUT_LOCAL_STORAGE_KEYS.feeRel)) || FORM_INPUT_DEFAULT_VALUES.feeRel,
- feeAbs:
- parseInt(window.localStorage.getItem(FORM_INPUT_LOCAL_STORAGE_KEYS.feeAbs), 10) || FORM_INPUT_DEFAULT_VALUES.feeAbs,
- minsize:
- parseInt(window.localStorage.getItem(FORM_INPUT_LOCAL_STORAGE_KEYS.minsize), 10) ||
- FORM_INPUT_DEFAULT_VALUES.minsize,
-})
-
-const renderOrderType = (val, t) => {
- if (isAbsoluteOffer(val)) {
+const initialFormValues = (): EarnFormValues => {
+ const feeRel = parseFloat(
+ window.localStorage.getItem(FORM_INPUT_LOCAL_STORAGE_KEYS.feeRel) ?? String(FORM_INPUT_DEFAULT_VALUES.feeRel),
+ )
+ const feeAbs = parseInt(
+ window.localStorage.getItem(FORM_INPUT_LOCAL_STORAGE_KEYS.feeAbs) ?? String(FORM_INPUT_DEFAULT_VALUES.feeAbs),
+ 10,
+ )
+ const minsize = parseInt(
+ window.localStorage.getItem(FORM_INPUT_LOCAL_STORAGE_KEYS.minsize) ?? String(FORM_INPUT_DEFAULT_VALUES.minsize),
+ 10,
+ )
+ const offertype =
+ window.localStorage.getItem(FORM_INPUT_LOCAL_STORAGE_KEYS.offertype) ?? FORM_INPUT_DEFAULT_VALUES.offertype
+ return {
+ offertype,
+ feeRel: isValidNumber(feeRel) ? feeRel : FORM_INPUT_DEFAULT_VALUES.feeRel,
+ feeAbs: isValidNumber(feeAbs) ? feeAbs : FORM_INPUT_DEFAULT_VALUES.feeAbs,
+ minsize: isValidNumber(minsize) ? minsize : FORM_INPUT_DEFAULT_VALUES.minsize,
+ }
+}
+
+const renderOfferType = (offer: Offer, t: TFunction) => {
+ if (isAbsoluteOffer(offer.ordertype)) {
return {t('earn.current.text_offer_type_absolute')}
}
- if (isRelativeOffer(val)) {
+ if (isRelativeOffer(offer.ordertype)) {
return {t('earn.current.text_offer_type_relative')}
}
- return {val}
+ return {offer.ordertype}
+}
+
+interface CurrentOfferProps {
+ offer: Offer
+ nickname: string
}
-function CurrentOffer({ offer, nickname }) {
+function CurrentOffer({ offer, nickname }: CurrentOfferProps) {
const { t } = useTranslation()
const settings = useSettings()
@@ -100,7 +123,7 @@ function CurrentOffer({ offer, nickname }) {
{nickname}:{offer.oid}
-
{renderOrderType(offer.ordertype, t)}
+ {renderOfferType(offer, t)}
@@ -109,7 +132,7 @@ function CurrentOffer({ offer, nickname }) {
{t('earn.current.text_cjfee')}
{isRelativeOffer(offer.ordertype) ? (
- <>{factorToPercentage(offer.cjfee)}%>
+ <>{factorToPercentage(parseFloat(offer.cjfee) || 0)}%>
) : (
<>
React.ReactNode | string
+ onSubmit: (values: EarnFormValues) => Promise
+ isLoading: boolean
+ disabled?: boolean
+}
+
+const EarnForm = ({
+ initialValues = FORM_INPUT_DEFAULT_VALUES,
+ submitButtonText,
+ onSubmit,
+ isLoading,
+ disabled = false,
+}: EarnFormProps) => {
+ const { t } = useTranslation()
+
+ const validate = (values: EarnFormValues) => {
+ const errors = {} as FormikErrors
+ const isRelOffer = isRelativeOffer(values.offertype)
+ const isAbsOffer = isAbsoluteOffer(values.offertype)
+
+ if (!isRelOffer && !isAbsOffer) {
+ // currently no need for translation, this should never occur -> input is controlled by toggle
+ errors.offertype = 'Offertype is not supported'
+ }
+
+ if (isRelOffer) {
+ if (typeof values.feeRel !== 'number' || values.feeRel < feeRelMin || values.feeRel > feeRelMax) {
+ errors.feeRel = t('earn.feedback_invalid_rel_fee', {
+ feeRelPercentageMin: `${factorToPercentage(feeRelMin)}%`,
+ feeRelPercentageMax: `${factorToPercentage(feeRelMax)}%`,
+ })
+ }
+ }
+
+ if (isAbsOffer) {
+ if (typeof values.feeAbs !== 'number' || values.feeAbs < 0) {
+ errors.feeAbs = t('earn.feedback_invalid_abs_fee')
+ }
+ }
+
+ if (typeof values.minsize !== 'number' || values.minsize < 0) {
+ errors.minsize = t('earn.feedback_invalid_min_amount')
+ }
+
+ return errors
+ }
+
+ return (
+
+ {({ handleSubmit, setFieldValue, handleChange, handleBlur, values, touched, errors, isSubmitting }) => (
+ <>
+
+
+ <>
+
+ {
+ checked && setFieldValue('offertype', tab.value, true)
+ }}
+ initialValue={values.offertype}
+ disabled={isLoading || isSubmitting}
+ />
+
+ {values.offertype === OFFERTYPE_REL ? (
+
+
+ {t('earn.label_rel_fee', {
+ fee: typeof values.feeRel === 'number' ? `(${factorToPercentage(values.feeRel)}%)` : '',
+ })}
+
+ {t('earn.description_rel_fee')}
+ {isLoading ? (
+
+
+
+ ) : (
+
+
+ %
+
+ {
+ const value = e.target.value || ''
+ setFieldValue('feeRel', value !== '' ? percentageToFactor(parseFloat(value)) : '', true)
+ }}
+ onBlur={handleBlur}
+ value={typeof values.feeRel === 'number' ? factorToPercentage(values.feeRel) : ''}
+ isValid={touched.feeRel && !errors.feeRel}
+ isInvalid={touched.feeRel && !!errors.feeRel}
+ min={0}
+ step={feeRelPercentageStep}
+ />
+ {errors.feeRel}
+
+ )}
+
+ ) : (
+
+
+ {t('earn.label_abs_fee', {
+ fee:
+ typeof values.feeAbs === 'number'
+ ? `(${values.feeAbs} ${values.feeAbs === 1 ? 'sat' : 'sats'})`
+ : '',
+ })}
+
+ {t('earn.description_abs_fee')}
+ {isLoading ? (
+
+
+
+ ) : (
+
+
+
+
+
+ {errors.feeAbs}
+
+ )}
+
+ )}
+
+
+ {t('earn.label_min_amount')}
+ {isLoading ? (
+
+
+
+ ) : (
+
+
+
+
+
+ {errors.minsize}
+
+ )}
+
+ >
+
+
+ {submitButtonText(isSubmitting)}
+
+
+ >
+ )}
+
+ )
+}
+
+const toStartMakerRequest = (values: EarnFormValues): Api.StartMakerRequest => {
+ // both fee properties need to be provided.
+ // prevent providing an invalid value by setting the ignored prop to zero
+ const cjfee_a = isAbsoluteOffer(values.offertype) ? values.feeAbs : 0
+ const cjfee_r = isRelativeOffer(values.offertype) ? values.feeRel : 0
+ return {
+ ordertype: values.offertype,
+ minsize: values.minsize,
+ cjfee_a,
+ cjfee_r,
+ }
+}
+
+interface EarnProps {
+ wallet: CurrentWallet
+}
+
+export default function Earn({ wallet }: EarnProps) {
const { t } = useTranslation()
const settings = useSettings()
const currentWalletInfo = useCurrentWalletInfo()
@@ -177,47 +421,46 @@ export default function Earn({ wallet }) {
const serviceInfo = useServiceInfo()
const reloadServiceInfo = useReloadServiceInfo()
- const [alert, setAlert] = useState(null)
- const [serviceInfoAlert, setServiceInfoAlert] = useState(null)
+ const [alert, setAlert] = useState()
+ const [serviceInfoAlert, setServiceInfoAlert] = useState()
const [isLoading, setIsLoading] = useState(true)
const [isSending, setIsSending] = useState(false)
const [isWaitingMakerStart, setIsWaitingMakerStart] = useState(false)
const [isWaitingMakerStop, setIsWaitingMakerStop] = useState(false)
const [isShowReport, setIsShowReport] = useState(false)
const [isShowOrderbook, setIsShowOrderbook] = useState(false)
+
+ const [initialValues, setInitialValues] = useState(initialFormValues())
+
const fidelityBonds = useMemo(() => {
return currentWalletInfo?.fidelityBondSummary.fbOutputs || []
}, [currentWalletInfo])
- const [moveToJarFidelityBondId, setMoveToJarFidelityBondId] = useState()
-
- const startMakerService = (ordertype, minsize, cjfee_a, cjfee_r) => {
- setIsSending(true)
- setIsWaitingMakerStart(true)
-
- const data = {
- ordertype,
- minsize,
- cjfee_a,
- cjfee_r,
- }
-
- // There is no response data to check if maker got started:
- // Wait for the websocket or session response!
- return (
- Api.postMakerStart({ ...wallet }, data)
- .then((res) => (res.ok ? true : Api.Helper.throwError(res)))
- // show the loader a little longer to avoid flickering
- .then((result) => new Promise((r) => setTimeout(() => r(result), 200)))
- .catch((e) => {
- setIsWaitingMakerStart(false)
- throw e
- })
- .finally(() => setIsSending(false))
- )
- }
+ const [moveToJarFidelityBondId, setMoveToJarFidelityBondId] = useState()
+
+ const startMakerService = useCallback(
+ (values: EarnFormValues) => {
+ setIsSending(true)
+ setIsWaitingMakerStart(true)
+
+ // There is no response data to check if maker got started:
+ // Wait for the websocket or session response!
+ return (
+ Api.postMakerStart({ ...wallet }, toStartMakerRequest(values))
+ .then((res) => (res.ok ? true : Api.Helper.throwError(res)))
+ // show the loader a little longer to avoid flickering
+ .then((result) => new Promise((r) => setTimeout(() => r(result), 200)))
+ .catch((e) => {
+ setIsWaitingMakerStart(false)
+ throw e
+ })
+ .finally(() => setIsSending(false))
+ )
+ },
+ [wallet],
+ )
- const stopMakerService = () => {
+ const stopMakerService = useCallback(() => {
setIsSending(true)
setIsWaitingMakerStop(true)
@@ -231,7 +474,7 @@ export default function Earn({ wallet }) {
throw e
})
.finally(() => setIsSending(false))
- }
+ }, [wallet])
useEffect(() => {
if (isSending) return
@@ -255,7 +498,7 @@ export default function Earn({ wallet }) {
useEffect(() => {
if (isSending) return
- const makerRunning = serviceInfo?.makerRunning
+ const makerRunning = serviceInfo?.makerRunning === true
const waitingForMakerToStart = isWaitingMakerStart && !makerRunning
setIsWaitingMakerStart(waitingForMakerToStart)
@@ -269,97 +512,73 @@ export default function Earn({ wallet }) {
if (!waiting && makerRunning) {
return { variant: 'success', message: t('earn.alert_running') }
} else if (!waiting) {
- return null
+ return undefined
}
return current
})
}, [isSending, serviceInfo, isWaitingMakerStart, isWaitingMakerStop, t])
- const reloadFidelityBonds = ({ delay }) => {
- const abortCtrl = new AbortController()
+ const reloadFidelityBonds = useCallback(
+ ({ delay }: { delay: number }) => {
+ const abortCtrl = new AbortController()
- setIsLoading(true)
+ setIsLoading(true)
- new Promise((resolve) => {
- setTimeout(async () => {
- resolve(await reloadCurrentWalletInfo.reloadUtxos({ signal: abortCtrl.signal }))
- }, delay)
- })
- .catch((err) => {
- if (abortCtrl.signal.aborted) return
- setAlert({ variant: 'danger', message: err.message })
- })
- .finally(() => {
- if (abortCtrl.signal.aborted) return
- setIsLoading(false)
+ new Promise((resolve) => {
+ setTimeout(async () => {
+ resolve(await reloadCurrentWalletInfo.reloadUtxos({ signal: abortCtrl.signal }))
+ }, delay)
})
- }
-
- const feeRelMin = 0.0
- const feeRelMax = 0.1 // 10%
- const feeRelPercentageStep = 0.0001
+ .catch((err) => {
+ if (abortCtrl.signal.aborted) return
+ setAlert({ variant: 'danger', message: err.message || t('global.errors.reason_unknown') })
+ })
+ .finally(() => {
+ if (abortCtrl.signal.aborted) return
+ setIsLoading(false)
+ })
+ },
+ [reloadCurrentWalletInfo, t],
+ )
- const initialValues = initialFormValues()
+ const onSubmitStart = useCallback(
+ async (values: EarnFormValues) => {
+ if (isLoading || isSending || isWaitingMakerStart || isWaitingMakerStop) {
+ return
+ }
- const validate = (values) => {
- const errors = {}
- const isRelOffer = isRelativeOffer(values.offertype)
- const isAbsOffer = isAbsoluteOffer(values.offertype)
+ setAlert(undefined)
- if (!isRelOffer && !isAbsOffer) {
- // currently no need for translation, this should never occur -> input is controlled by toggle
- errors.offertype = 'Offertype is not supported'
- }
+ try {
+ persistFormValues(values)
+ setInitialValues(initialFormValues())
- if (isRelOffer) {
- if (typeof values.feeRel !== 'number' || values.feeRel < feeRelMin || values.feeRel > feeRelMax) {
- errors.feeRel = t('earn.feedback_invalid_rel_fee', {
- feeRelPercentageMin: `${factorToPercentage(feeRelMin)}%`,
- feeRelPercentageMax: `${factorToPercentage(feeRelMax)}%`,
- })
- }
- }
+ setServiceInfoAlert({ variant: 'success', message: t('earn.alert_starting') })
- if (isAbsOffer) {
- if (typeof values.feeAbs !== 'number' || values.feeAbs < 0) {
- errors.feeAbs = t('earn.feedback_invalid_abs_fee')
+ await startMakerService(values)
+ } catch (e: any) {
+ setServiceInfoAlert(undefined)
+ setAlert({ variant: 'danger', message: e.message || t('global.errors.reason_unknown') })
}
- }
-
- if (typeof values.minsize !== 'number' || values.minsize < 0) {
- errors.minsize = t('earn.feedback_invalid_min_amount')
- }
-
- return errors
- }
+ },
+ [startMakerService, isLoading, isSending, isWaitingMakerStart, isWaitingMakerStop, t],
+ )
- const onSubmit = async (values) => {
+ const onSubmitStop = useCallback(async () => {
if (isLoading || isSending || isWaitingMakerStart || isWaitingMakerStop) {
return
}
- setAlert(null)
+ setAlert(undefined)
try {
- if (serviceInfo?.makerRunning === true) {
- setServiceInfoAlert({ variant: 'success', message: t('earn.alert_stopping') })
- await stopMakerService()
- } else {
- persistFormValues(values)
-
- setServiceInfoAlert({ variant: 'success', message: t('earn.alert_starting') })
-
- // both fee properties need to be provided.
- // prevent providing an invalid value by setting the ignored prop to zero
- const feeAbs = isAbsoluteOffer(values.offertype) ? values.feeAbs : 0
- const feeRel = isRelativeOffer(values.offertype) ? values.feeRel : 0
- await startMakerService(values.offertype, values.minsize, feeAbs, feeRel)
- }
- } catch (e) {
- setServiceInfoAlert(null)
- setAlert({ variant: 'danger', message: e.message })
+ setServiceInfoAlert({ variant: 'success', message: t('earn.alert_stopping') })
+ await stopMakerService()
+ } catch (e: any) {
+ setServiceInfoAlert(undefined)
+ setAlert({ variant: 'danger', message: e.message || t('global.errors.reason_unknown') })
}
- }
+ }, [stopMakerService, isLoading, isSending, isWaitingMakerStart, isWaitingMakerStop, t])
return (
@@ -382,7 +601,7 @@ export default function Earn({ wallet }) {
(serviceInfo?.offers && serviceInfo?.nickname ? (
<>
{serviceInfo.offers.map((offer, index) => (
-
+
))}
>
) : (
@@ -465,162 +684,18 @@ export default function Earn({ wallet }) {
>
)}
- {!serviceInfo?.coinjoinInProgress && (
-
- {({ handleSubmit, setFieldValue, handleChange, handleBlur, values, touched, errors, isSubmitting }) => (
- <>
-
- {!serviceInfo?.makerRunning && !isWaitingMakerStart && !isWaitingMakerStop && (
-
- <>
-
- {
- checked && setFieldValue('offertype', tab.value, true)
- }}
- initialValue={values.offertype}
- disabled={isLoading || isSubmitting}
- />
-
- {values.offertype === OFFERTYPE_REL ? (
-
-
- {t('earn.label_rel_fee', {
- fee:
- typeof values.feeRel === 'number' ? `(${factorToPercentage(values.feeRel)}%)` : '',
- })}
-
-
- {t('earn.description_rel_fee')}
-
- {isLoading ? (
-
-
-
- ) : (
-
-
- %
-
- {
- const value = e.target.value || ''
- setFieldValue('feeRel', value !== '' ? percentageToFactor(value) : '', true)
- }}
- onBlur={handleBlur}
- value={typeof values.feeRel === 'number' ? factorToPercentage(values.feeRel) : ''}
- isValid={touched.feeRel && !errors.feeRel}
- isInvalid={touched.feeRel && !!errors.feeRel}
- min={0}
- step={feeRelPercentageStep}
- />
- {errors.feeRel}
-
- )}
-
- ) : (
-
-
- {t('earn.label_abs_fee', {
- fee:
- typeof values.feeAbs === 'number'
- ? `(${values.feeAbs} ${values.feeAbs === 1 ? 'sat' : 'sats'})`
- : '',
- })}
-
-
- {t('earn.description_abs_fee')}
-
- {isLoading ? (
-
-
-
- ) : (
-
-
-
-
-
- {errors.feeAbs}
-
- )}
-
- )}
-
- {t('earn.label_min_amount')}
- {isLoading ? (
-
-
-
- ) : (
-
-
-
-
-
- {errors.minsize}
-
- )}
-
- >
-
- )}
-
-
+ {!serviceInfo?.coinjoinInProgress && (
+ <>
+ {!serviceInfo?.makerRunning && !isWaitingMakerStart && !isWaitingMakerStop ? (
+ {
+ return (
+ <>
{isWaitingMakerStart || isWaitingMakerStop ? (
<>
{serviceInfo?.makerRunning === true ? t('earn.button_stop') : t('earn.button_start')}>
)}
-
-
-
- >
+ >
+ )
+ }}
+ />
+ ) : (
+
+ {({ handleSubmit, isSubmitting }) => (
+
+
+
+ {isWaitingMakerStart || isWaitingMakerStop ? (
+ <>
+
+ {isWaitingMakerStart && t('earn.text_starting')}
+ {isWaitingMakerStop && t('earn.text_stopping')}
+ >
+ ) : (
+ <>{t('earn.button_stop')}>
+ )}
+
+
+
+ )}
+
)}
-
+ >
)}
@@ -651,7 +766,7 @@ export default function Earn({ wallet }) {
setIsShowOrderbook(false)}
- nickname={serviceInfo?.nickname}
+ nickname={serviceInfo?.nickname ?? undefined}
/>
{
}, {} as AddressSummary)
}
-const toFidelityBondSummary = (res: UtxosResponse): FidenlityBondSummary => {
+const toFidelityBondSummary = (res: UtxosResponse): FidelityBondSummary => {
const fbOutputs = res.utxos
.filter((utxo) => fb.utxo.isFidelityBond(utxo))
.sort((a, b) => {
diff --git a/src/libs/JmWalletApi.ts b/src/libs/JmWalletApi.ts
index d6329970..ca85ae7a 100644
--- a/src/libs/JmWalletApi.ts
+++ b/src/libs/JmWalletApi.ts
@@ -99,12 +99,12 @@ interface WalletUnlockRequest {
// only support starting the maker with native segwit offers
type RelOfferType = 'sw0reloffer'
type AbsOfferType = 'sw0absoffer'
-type OrderType = RelOfferType | AbsOfferType
+type OfferType = RelOfferType | AbsOfferType | string
interface StartMakerRequest {
cjfee_a: AmountSats
cjfee_r: number
- ordertype: OrderType
+ ordertype: OfferType
minsize: AmountSats
}
@@ -553,6 +553,7 @@ export {
JmApiError,
ApiAuthContext,
StartSchedulerRequest,
+ StartMakerRequest,
WalletRequestContext,
ApiToken,
WalletFileName,
@@ -563,5 +564,6 @@ export {
UtxoId,
Mixdepth,
AmountSats,
+ OfferType,
BitcoinAddress,
}