Fix swap btc + fix bot stoping

This commit is contained in:
2025-07-06 15:50:50 +07:00
parent f973be2e08
commit 46b43bce1a
3 changed files with 291 additions and 233 deletions

View File

@@ -24,7 +24,7 @@ public class SwapTokensRequest
/// The amount to swap /// The amount to swap
/// </summary> /// </summary>
[Required] [Required]
[Range(0.000001, double.MaxValue, ErrorMessage = "Amount must be greater than 0")] [Range(0.0000000000001, double.MaxValue, ErrorMessage = "Amount must be greater than 0")]
public double Amount { get; set; } public double Amount { get; set; }
/// <summary> /// <summary>

View File

@@ -224,7 +224,7 @@ public class TradingBot : Bot, ITradingBot
{ {
// Check broker balance before running // Check broker balance before running
var balance = await ExchangeService.GetBalance(Account, false); var balance = await ExchangeService.GetBalance(Account, false);
if (balance < Constants.GMX.Config.MinimumPositionAmount) if (balance < Constants.GMX.Config.MinimumPositionAmount && Positions.All(p => p.IsFinished()))
{ {
await LogWarning( await LogWarning(
$"Balance on broker is below {Constants.GMX.Config.MinimumPositionAmount} USD (actual: {balance}). Stopping bot {Identifier} and saving backup."); $"Balance on broker is below {Constants.GMX.Config.MinimumPositionAmount} USD (actual: {balance}). Stopping bot {Identifier} and saving backup.");

View File

@@ -24,6 +24,14 @@ interface SwapFormInput {
allowedSlippage: number allowedSlippage: number
} }
interface ValidationErrorResponse {
type: string
title: string
status: number
errors: Record<string, string[]>
traceId: string
}
const SwapModal: React.FC<SwapModalProps> = ({ const SwapModal: React.FC<SwapModalProps> = ({
isOpen, isOpen,
onClose, onClose,
@@ -32,6 +40,7 @@ const SwapModal: React.FC<SwapModalProps> = ({
availableAmount, availableAmount,
}) => { }) => {
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [validationErrors, setValidationErrors] = useState<Record<string, string[]>>({})
const {error, setError, handleApiErrorWithToast} = useApiError() const {error, setError, handleApiErrorWithToast} = useApiError()
const {apiUrl} = useApiUrlStore() const {apiUrl} = useApiUrlStore()
const client = new AccountClient({}, apiUrl) const client = new AccountClient({}, apiUrl)
@@ -62,6 +71,7 @@ const SwapModal: React.FC<SwapModalProps> = ({
const t = new Toast(`Swapping ${form.amount} ${form.fromTicker} to ${form.toTicker} on ${account.name}`) const t = new Toast(`Swapping ${form.amount} ${form.fromTicker} to ${form.toTicker} on ${account.name}`)
setIsLoading(true) setIsLoading(true)
setError(null) setError(null)
setValidationErrors({})
try { try {
const result = await client.account_SwapGmxTokens( const result = await client.account_SwapGmxTokens(
@@ -85,16 +95,31 @@ const SwapModal: React.FC<SwapModalProps> = ({
setError(errorMessage) setError(errorMessage)
t.update('error', `Swap failed: ${errorMessage}`) t.update('error', `Swap failed: ${errorMessage}`)
} }
} catch (err) { } catch (err: any) {
// Handle validation errors from API
if (err.response?.data && typeof err.response.data === 'object') {
const errorData = err.response.data as ValidationErrorResponse
console.log(errorData)
if (errorData.errors && typeof errorData.errors === 'object') {
setValidationErrors(errorData.errors)
const errorMessages = Object.values(errorData.errors).flat()
const errorMessage = errorMessages.join(', ')
setError(errorMessage)
t.update('error', `Validation failed: ${errorMessage}`)
} else {
handleApiErrorWithToast(err, t) handleApiErrorWithToast(err, t)
}
} else {
handleApiErrorWithToast(err, t)
}
} finally { } finally {
setIsLoading(false) setIsLoading(false)
} }
} }
const handleFormSubmit = (e: React.FormEvent) => { const handleFormSubmit = async (e: React.FormEvent) => {
e.preventDefault() e.preventDefault()
handleSubmit(onSubmit)(e) await handleSubmit(onSubmit)(e)
} }
const modalContent = ( const modalContent = (
@@ -120,6 +145,18 @@ const SwapModal: React.FC<SwapModalProps> = ({
</div> </div>
<form onSubmit={handleFormSubmit}> <form onSubmit={handleFormSubmit}>
{Object.keys(validationErrors).length > 0 && (
<div className="alert alert-error mb-4">
<div>
<h4 className="font-bold">Validation Errors:</h4>
{Object.entries(validationErrors).map(([field, errors]) => (
<div key={field} className="mt-1">
<strong>{field}:</strong> {errors.join(', ')}
</div>
))}
</div>
</div>
)}
<div className="space-y-4 mb-4"> <div className="space-y-4 mb-4">
<FormInput label="To Ticker" htmlFor="toTicker"> <FormInput label="To Ticker" htmlFor="toTicker">
<select <select
@@ -147,20 +184,27 @@ const SwapModal: React.FC<SwapModalProps> = ({
type="number" type="number"
step="any" step="any"
placeholder="Enter amount to swap" placeholder="Enter amount to swap"
className="input input-bordered w-full mb-2" className={`input input-bordered w-full mb-2 ${validationErrors.Amount ? 'input-error' : ''}`}
{...register('amount', { {...register('amount', {
valueAsNumber: true, valueAsNumber: true,
min: 0.0001, min: 0.00000000000001,
max: availableAmount, max: availableAmount,
required: true required: true
})} })}
/> />
{validationErrors.Amount && (
<div className="text-error text-xs mt-1">
{validationErrors.Amount.map((error, index) => (
<div key={index}>{error}</div>
))}
</div>
)}
<div className="w-full"> <div className="w-full">
<input <input
type="range" type="range"
min="0" min="0"
max={availableAmount} max={availableAmount}
step={availableAmount / 100} step={0.00000000000001}
className="range range-primary w-full" className="range range-primary w-full"
value={watchedAmount || 0} value={watchedAmount || 0}
onChange={(e) => { onChange={(e) => {
@@ -201,7 +245,7 @@ const SwapModal: React.FC<SwapModalProps> = ({
type="number" type="number"
step="0.1" step="0.1"
placeholder="0.5" placeholder="0.5"
className="input input-bordered w-full" className={`input input-bordered w-full ${validationErrors.AllowedSlippage ? 'input-error' : ''}`}
{...register('allowedSlippage', { {...register('allowedSlippage', {
valueAsNumber: true, valueAsNumber: true,
min: 0.1, min: 0.1,
@@ -209,6 +253,13 @@ const SwapModal: React.FC<SwapModalProps> = ({
value: 0.5 value: 0.5
})} })}
/> />
{validationErrors.AllowedSlippage && (
<div className="text-error text-xs mt-1">
{validationErrors.AllowedSlippage.map((error, index) => (
<div key={index}>{error}</div>
))}
</div>
)}
</FormInput> </FormInput>
{selectedOrderType === 'limit' && ( {selectedOrderType === 'limit' && (
@@ -217,9 +268,16 @@ const SwapModal: React.FC<SwapModalProps> = ({
type="number" type="number"
step="any" step="any"
placeholder="Enter trigger ratio" placeholder="Enter trigger ratio"
className="input input-bordered w-full" className={`input input-bordered w-full ${validationErrors.TriggerRatio ? 'input-error' : ''}`}
{...register('triggerRatio', {valueAsNumber: true})} {...register('triggerRatio', {valueAsNumber: true})}
/> />
{validationErrors.TriggerRatio && (
<div className="text-error text-xs mt-1">
{validationErrors.TriggerRatio.map((error, index) => (
<div key={index}>{error}</div>
))}
</div>
)}
</FormInput> </FormInput>
)} )}