Skip to content

Commit 6ba673d

Browse files
committed
feat: replace generic Error throws with typed error classes
Add ZeroExValidationError, ZeroExUnsupportedOperationError, ZeroExTransactionRevertedError, and ZeroExTimeoutError. Replace all generic Error instances in interface methods with the appropriate typed class. Export new classes from index.js. Update README fee mapping table with legacy fee/bridgeFee column and add new error types to the error reference table.
1 parent e314199 commit 6ba673d

4 files changed

Lines changed: 76 additions & 16 deletions

File tree

‎README.md‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,11 @@ For native ETH (or any chain's native token) as a **buy token**, use `0xEeeeeEee
153153

154154
## Fee mapping
155155

156-
| 0x response field | `SwidgeFeeType` | Notes |
157-
|---|---|---|
158-
| `totalNetworkFee` | `network` | Denominated in the chain's native token (e.g. ETH) |
159-
| `fees.zeroExFee` | `protocol` | 0x protocol fee |
160-
| `fees.integratorFee` | `affiliate` | Integrator / referral fee |
156+
| 0x response field | `SwidgeFeeType` | Notes | Legacy mapping |
157+
|---|---|---|---|
158+
| `totalNetworkFee` | `network` | Denominated in the chain's native token (e.g. ETH) | `fee` |
159+
| `fees.zeroExFee` | `protocol` | 0x protocol fee | `bridgeFee` |
160+
| `fees.integratorFee` | `affiliate` | Integrator / referral fee | not visible |
161161

162162
Fee caps (`maxNetworkFeeBps`, `maxProtocolFeeBps`) are only enforced when the fee token matches the sell token. Cross-token comparisons are skipped because price data is not available in the API response.
163163

@@ -171,6 +171,10 @@ Fee caps (`maxNetworkFeeBps`, `maxProtocolFeeBps`) are only enforced when the fe
171171
| `ZeroExInsufficientLiquidityError` | `liquidityAvailable: false` in the price response |
172172
| `ZeroExFeeLimitExceededError` | A quoted fee exceeds a configured `maxNetworkFeeBps` or `maxProtocolFeeBps` cap |
173173
| `ZeroExReadOnlyError` | `swidge` is called without a full signing account |
174+
| `ZeroExValidationError` | Invalid or missing input parameters |
175+
| `ZeroExUnsupportedOperationError` | An unsupported operation is requested (e.g. cross-chain `toChain`) |
176+
| `ZeroExTransactionRevertedError` | The swap transaction reverted on-chain |
177+
| `ZeroExTimeoutError` | Timed out waiting for transaction confirmation |
174178
| `NotImplementedError` | `getSupportedTokens()` is called |
175179

176180
---

‎index.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@
3333
/** @typedef {import('./src/0x-protocol.js').ZeroExProtocolConfig} ZeroExProtocolConfig */
3434

3535
export { default, default as ZeroExProtocol } from './src/0x-protocol.js'
36-
export { ZeroExApiError, ZeroExInsufficientLiquidityError, ZeroExFeeLimitExceededError, ZeroExReadOnlyError } from './src/errors.js'
36+
export { ZeroExApiError, ZeroExInsufficientLiquidityError, ZeroExFeeLimitExceededError, ZeroExReadOnlyError, ZeroExValidationError, ZeroExUnsupportedOperationError, ZeroExTransactionRevertedError, ZeroExTimeoutError } from './src/errors.js'
3737
export { ISwidgeProtocol } from '@tetherto/wdk-wallet/protocols'

‎src/0x-protocol.js‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { SwidgeProtocol } from '@tetherto/wdk-wallet/protocols'
1818
import { NotImplementedError } from '@tetherto/wdk-wallet'
1919

2020
import ZeroExApiClient from './api-client.js'
21-
import { ZeroExFeeLimitExceededError, ZeroExInsufficientLiquidityError, ZeroExReadOnlyError } from './errors.js'
21+
import { ZeroExFeeLimitExceededError, ZeroExInsufficientLiquidityError, ZeroExReadOnlyError, ZeroExValidationError, ZeroExUnsupportedOperationError, ZeroExTransactionRevertedError, ZeroExTimeoutError } from './errors.js'
2222

2323
/** @typedef {import('@tetherto/wdk-wallet').IWalletAccount} IWalletAccount */
2424
/** @typedef {import('@tetherto/wdk-wallet').IWalletAccountReadOnly} IWalletAccountReadOnly */
@@ -154,13 +154,13 @@ export default class ZeroExProtocol extends SwidgeProtocol {
154154
*/
155155
async quoteSwidge (options) {
156156
if (options.fromTokenAmount == null && options.toTokenAmount == null) {
157-
throw new Error('Either fromTokenAmount (exact-in) or toTokenAmount (exact-out) must be provided.')
157+
throw new ZeroExValidationError('Either fromTokenAmount (exact-in) or toTokenAmount (exact-out) must be provided.')
158158
}
159159

160160
const chainId = Number(this._config.chainId)
161161

162162
if (options.toChain != null && Number(options.toChain) !== chainId) {
163-
throw new Error(
163+
throw new ZeroExUnsupportedOperationError(
164164
`Cross-chain bridging is not supported. toChain (${options.toChain}) must match the configured chainId (${chainId}).`
165165
)
166166
}
@@ -242,7 +242,7 @@ export default class ZeroExProtocol extends SwidgeProtocol {
242242
const chainId = Number(this._config.chainId)
243243

244244
if (options.toChain != null && Number(options.toChain) !== chainId) {
245-
throw new Error(
245+
throw new ZeroExUnsupportedOperationError(
246246
`Cross-chain bridging is not supported. toChain (${options.toChain}) must match the configured chainId (${chainId}).`
247247
)
248248
}
@@ -280,7 +280,7 @@ export default class ZeroExProtocol extends SwidgeProtocol {
280280
// Handle ERC-20 approval if required
281281
if (!isNative && !this._config.skipApproval && quote.issues?.allowance != null) {
282282
if (typeof this._account.approve !== 'function') {
283-
throw new Error(
283+
throw new ZeroExValidationError(
284284
'Cannot approve the sell token: the wallet account does not support ERC-20 approvals.'
285285
)
286286
}
@@ -332,7 +332,7 @@ export default class ZeroExProtocol extends SwidgeProtocol {
332332
*/
333333
async getSwidgeStatus (id, options) {
334334
if (typeof id !== 'string' || id.length === 0) {
335-
throw new Error('Invalid swidge identifier.')
335+
throw new ZeroExValidationError('Invalid swidge identifier.')
336336
}
337337

338338
let chainId, hash
@@ -343,7 +343,7 @@ export default class ZeroExProtocol extends SwidgeProtocol {
343343
} else {
344344
const fromChain = options?.fromChain ?? this._config.chainId
345345
if (fromChain == null) {
346-
throw new Error(
346+
throw new ZeroExValidationError(
347347
"Cannot resolve the source chain: pass an id in the '<chainId>:<hash>' format, or provide the fromChain status option."
348348
)
349349
}
@@ -352,7 +352,7 @@ export default class ZeroExProtocol extends SwidgeProtocol {
352352
}
353353

354354
if (!hash.startsWith('0x') || hash.length < 10) {
355-
throw new Error(`Invalid transaction hash in swidge identifier: '${hash}'.`)
355+
throw new ZeroExValidationError(`Invalid transaction hash in swidge identifier: '${hash}'.`)
356356
}
357357

358358
/** @type {SwidgeTransaction[]} */
@@ -554,13 +554,13 @@ export default class ZeroExProtocol extends SwidgeProtocol {
554554
if (receipt) {
555555
const success = receipt.status === 1 || receipt.status === 1n || receipt.status === true
556556
if (!success) {
557-
throw new Error(`Transaction '${hash}' reverted.`)
557+
throw new ZeroExTransactionRevertedError(hash)
558558
}
559559
return receipt
560560
}
561561
await new Promise(resolve => setTimeout(resolve, intervalMs))
562562
}
563563

564-
throw new Error(`Timed out waiting for transaction '${hash}' to be mined.`)
564+
throw new ZeroExTimeoutError(hash)
565565
}
566566
}

‎src/errors.js‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,62 @@ export class ZeroExReadOnlyError extends Error {
6060
}
6161
}
6262

63+
/**
64+
* Thrown when invalid or missing input parameters are passed to an interface method.
65+
*/
66+
export class ZeroExValidationError extends Error {
67+
/**
68+
* @param {string} message
69+
*/
70+
constructor (message) {
71+
super(message)
72+
this.name = 'ZeroExValidationError'
73+
}
74+
}
75+
76+
/**
77+
* Thrown when an operation is not supported by this module (e.g. cross-chain bridging).
78+
*/
79+
export class ZeroExUnsupportedOperationError extends Error {
80+
/**
81+
* @param {string} message
82+
*/
83+
constructor (message) {
84+
super(message)
85+
this.name = 'ZeroExUnsupportedOperationError'
86+
}
87+
}
88+
89+
/**
90+
* Thrown when a swap transaction reverts on-chain.
91+
*/
92+
export class ZeroExTransactionRevertedError extends Error {
93+
/**
94+
* @param {string} hash - The transaction hash that reverted.
95+
*/
96+
constructor (hash) {
97+
super(`Transaction '${hash}' reverted.`)
98+
this.name = 'ZeroExTransactionRevertedError'
99+
/** @type {string} */
100+
this.hash = hash
101+
}
102+
}
103+
104+
/**
105+
* Thrown when polling for a transaction receipt exceeds the timeout.
106+
*/
107+
export class ZeroExTimeoutError extends Error {
108+
/**
109+
* @param {string} hash - The transaction hash that timed out.
110+
*/
111+
constructor (hash) {
112+
super(`Timed out waiting for transaction '${hash}' to be mined.`)
113+
this.name = 'ZeroExTimeoutError'
114+
/** @type {string} */
115+
this.hash = hash
116+
}
117+
}
118+
63119
/**
64120
* Thrown when a quoted fee exceeds a configured fee cap.
65121
*/

0 commit comments

Comments
 (0)