Skip to content

Commit 043c9e6

Browse files
authored
Merge pull request #446 from EdgeApp/sam/nexchange-permission-error
Improve n.exchange error handling to detect georestriction errors
2 parents 85c62c7 + c908ac6 commit 043c9e6

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
- fixed: Map `mayachain` pluginId to MAYA chain correctly and remove non-existent `cacao` pluginId
6+
- fixed: Translate n.exchange IP restriction errors to SwapPermissionError.
67

78
## 2.42.1 (2026-03-06)
89

src/swap/central/nexchange.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {
33
asArray,
44
asDate,
55
asEither,
6+
asJSON,
7+
asMaybe,
68
asNull,
79
asNumber,
810
asObject,
@@ -19,7 +21,8 @@ import {
1921
EdgeSwapRequest,
2022
SwapAboveLimitError,
2123
SwapBelowLimitError,
22-
SwapCurrencyError
24+
SwapCurrencyError,
25+
SwapPermissionError
2326
} from 'edge-core-js/types'
2427

2528
import { nexchange as nexchangeMapping } from '../../mappings/nexchange'
@@ -104,6 +107,12 @@ function formatCurrency(
104107
}
105108
}
106109

110+
// Cleaner for Nexchange error responses, e.g. {"non_field_errors":["User's IP has risk."]}
111+
// Uses asMaybe so it returns null instead of throwing on unexpected shapes
112+
const asErrorResponse = asMaybe(
113+
asJSON(asObject({ non_field_errors: asArray(asString) }))
114+
)
115+
107116
const asRateV2 = asObject({
108117
// Fields validated but not currently used: pair, from, to, withdrawal_fee
109118
// These are kept for API validation and potential future use
@@ -187,9 +196,20 @@ export function makeNexchangePlugin(
187196
const text = await response.text()
188197
if (!response.ok) {
189198
log.warn('Nexchange response:', text)
199+
190200
if (response.status === 404 && request != null) {
191201
throw new SwapCurrencyError(swapInfo, request)
192202
}
203+
204+
if (response.status === 400) {
205+
const errorData = asErrorResponse(text)
206+
if (
207+
errorData?.non_field_errors.includes("User's IP has risk.") === true
208+
) {
209+
throw new SwapPermissionError(swapInfo, 'geoRestriction')
210+
}
211+
}
212+
193213
throw new Error(
194214
`Nexchange returned error code ${response.status}: ${text}`
195215
)

0 commit comments

Comments
 (0)