@sodax/sdk 1.5.7-beta → 2.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -7
- package/ai-exported/AGENTS.md +99 -0
- package/ai-exported/integration/README.md +41 -0
- package/ai-exported/integration/ai-rules.md +75 -0
- package/ai-exported/integration/architecture.md +519 -0
- package/ai-exported/integration/chain-specifics.md +189 -0
- package/ai-exported/integration/features/README.md +19 -0
- package/ai-exported/integration/features/auxiliary-services.md +189 -0
- package/ai-exported/integration/features/bridge.md +136 -0
- package/ai-exported/integration/features/dex.md +182 -0
- package/ai-exported/integration/features/icx-bnusd-baln.md +181 -0
- package/ai-exported/integration/features/money-market.md +198 -0
- package/ai-exported/integration/features/staking.md +166 -0
- package/ai-exported/integration/features/swap.md +207 -0
- package/ai-exported/integration/quickstart.md +213 -0
- package/ai-exported/integration/recipes/README.md +21 -0
- package/ai-exported/integration/recipes/backend-server-init.md +69 -0
- package/ai-exported/integration/recipes/chain-key-narrowing.md +65 -0
- package/ai-exported/integration/recipes/gas-estimation.md +33 -0
- package/ai-exported/integration/recipes/initialize-sodax.md +53 -0
- package/ai-exported/integration/recipes/raw-tx-flow.md +71 -0
- package/ai-exported/integration/recipes/result-and-errors.md +104 -0
- package/ai-exported/integration/recipes/signed-tx-flow.md +46 -0
- package/ai-exported/integration/recipes/testing.md +101 -0
- package/ai-exported/integration/reference/README.md +18 -0
- package/ai-exported/integration/reference/chain-keys.md +67 -0
- package/ai-exported/integration/reference/error-codes.md +165 -0
- package/ai-exported/integration/reference/glossary.md +32 -0
- package/ai-exported/integration/reference/public-api.md +138 -0
- package/ai-exported/integration/reference/wallet-providers.md +62 -0
- package/ai-exported/migration/README.md +58 -0
- package/ai-exported/migration/ai-rules.md +80 -0
- package/ai-exported/migration/breaking-changes/architecture.md +342 -0
- package/ai-exported/migration/breaking-changes/result-and-errors.md +363 -0
- package/ai-exported/migration/breaking-changes/type-system.md +321 -0
- package/ai-exported/migration/checklist.md +61 -0
- package/ai-exported/migration/features/README.md +35 -0
- package/ai-exported/migration/features/auxiliary-services.md +156 -0
- package/ai-exported/migration/features/bridge.md +125 -0
- package/ai-exported/migration/features/dex.md +143 -0
- package/ai-exported/migration/features/icx-bnusd-baln.md +151 -0
- package/ai-exported/migration/features/money-market.md +214 -0
- package/ai-exported/migration/features/staking.md +138 -0
- package/ai-exported/migration/features/swap.md +198 -0
- package/ai-exported/migration/recipes.md +288 -0
- package/ai-exported/migration/reference/README.md +18 -0
- package/ai-exported/migration/reference/deleted-exports.md +126 -0
- package/ai-exported/migration/reference/error-code-crosswalk.md +104 -0
- package/ai-exported/migration/reference/return-shapes.md +49 -0
- package/ai-exported/migration/reference/sodax-config.md +52 -0
- package/dist/index.cjs +32076 -31544
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8604 -7136
- package/dist/index.d.ts +8604 -7136
- package/dist/index.mjs +31893 -31402
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -12
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# Architecture breaking changes — v1 → v2
|
|
2
|
+
|
|
3
|
+
The structural changes that reshaped the SDK at the service / runtime layer. Read after [`type-system.md`](type-system.md) — by the time you arrive here, your imports should compile and the rest is wiring.
|
|
4
|
+
|
|
5
|
+
The four load-bearing shifts:
|
|
6
|
+
|
|
7
|
+
1. **Per-chain `*SpokeProvider` classes are deleted.** Routing is by chain key, dispatched internally by `SpokeService`.
|
|
8
|
+
2. **Static lookup tables (`hubAssets`, `moneyMarketSupportedTokens`, `SodaTokens`) are deleted.** Lookups go through `sodax.config.*`.
|
|
9
|
+
3. **Relay flow is centralised.** Two functions (`relayTxAndWaitPacket`, `submitTransaction`) and one mapper (`mapRelayFailure`) replace per-feature relay helpers.
|
|
10
|
+
4. **Invariants and guards are unified.** `sodaxInvariant` + per-feature aliases (`swapInvariant`, `mmInvariant`, etc.) and `isSodaxError` / `isFeatureError` replace ad-hoc throws and module-specific type guards.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. Spoke-provider deletion
|
|
15
|
+
|
|
16
|
+
### What's gone
|
|
17
|
+
|
|
18
|
+
These v1 classes and their union are **deleted**:
|
|
19
|
+
|
|
20
|
+
- `EvmSpokeProvider`
|
|
21
|
+
- `SonicSpokeProvider`
|
|
22
|
+
- `SolanaSpokeProvider`
|
|
23
|
+
- `SuiSpokeProvider`
|
|
24
|
+
- `IconSpokeProvider`
|
|
25
|
+
- `InjectiveSpokeProvider`
|
|
26
|
+
- `StellarSpokeProvider`
|
|
27
|
+
- `StacksSpokeProvider`
|
|
28
|
+
- `BitcoinSpokeProvider`
|
|
29
|
+
- `NearSpokeProvider`
|
|
30
|
+
- The union type `SpokeProvider`
|
|
31
|
+
- The instance-test functions: `isEvmSpokeProvider`, `isSolanaSpokeProvider`, `isBitcoinSpokeProvider`, `isStellarSpokeProvider`, `isIconSpokeProvider`, `isSuiSpokeProvider`, `isInjectiveSpokeProvider`, `isStacksSpokeProvider`, `isNearSpokeProvider`, `isSonicSpokeProvider`.
|
|
32
|
+
|
|
33
|
+
### What replaces them
|
|
34
|
+
|
|
35
|
+
A single internal router, `SpokeService`, owned by the `Sodax` instance. It holds one per-chain-family service (`EvmSpokeService`, `SolanaSpokeService`, …) and exposes `getSpokeService(chainKey)` for internal feature services. **Consumers never construct or hold a reference to a spoke service.** They pass `walletProvider` and a `srcChainKey` literal, and the SDK dispatches.
|
|
36
|
+
|
|
37
|
+
### Migration mechanics
|
|
38
|
+
|
|
39
|
+
#### v1: construct + pass
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
// v1
|
|
43
|
+
const evmWp = new EvmWalletProvider({ privateKey: '0x…', rpcUrl: '…' });
|
|
44
|
+
const sourceProvider = new EvmSpokeProvider({ walletProvider: evmWp, chainConfig: ARBITRUM_MAINNET_CONFIG });
|
|
45
|
+
|
|
46
|
+
await sodax.swaps.createIntent({ intentParams, spokeProvider: sourceProvider });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
#### v2: pass directly
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// v2
|
|
53
|
+
const evmWp = new EvmWalletProvider({ privateKey: '0x…', rpcUrl: '…' });
|
|
54
|
+
|
|
55
|
+
await sodax.swaps.createIntent({
|
|
56
|
+
params: { ...intentParams, srcChainKey: ChainKeys.ARBITRUM_MAINNET, srcAddress },
|
|
57
|
+
raw: false,
|
|
58
|
+
walletProvider: evmWp,
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The chain config is no longer something the consumer constructs — it's loaded by `ConfigService` from the backend (with a fallback to packaged defaults). The chain key on the payload tells the SDK which spoke service to route to.
|
|
63
|
+
|
|
64
|
+
### Replacing instance tests with chain-key guards
|
|
65
|
+
|
|
66
|
+
```diff
|
|
67
|
+
- if (isBitcoinSpokeProvider(provider)) { /* … */ }
|
|
68
|
+
+ if (chainKey === ChainKeys.BITCOIN_MAINNET) { /* … */ }
|
|
69
|
+
|
|
70
|
+
- if (provider instanceof StellarSpokeProvider) { /* … */ }
|
|
71
|
+
+ if (chainKey === ChainKeys.STELLAR_MAINNET) { /* … */ }
|
|
72
|
+
|
|
73
|
+
- if (isEvmSpokeProvider(provider)) { /* … */ }
|
|
74
|
+
+ if (getChainType(chainKey) === 'EVM') { /* … */ }
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`getChainType(chainKey)` (from `@sodax/sdk`) returns `'EVM' | 'BITCOIN' | 'SOLANA' | 'STELLAR' | 'SUI' | 'ICON' | 'INJECTIVE' | 'STACKS' | 'NEAR'` and is the canonical chain-family discriminator.
|
|
78
|
+
|
|
79
|
+
Family-level helper guards (`isEvmChainKeyType`, `isBitcoinChainKeyType`, `isSolanaChainKeyType`, etc.) are also exported from `@sodax/sdk` for cases where you want a typed boolean.
|
|
80
|
+
|
|
81
|
+
### Replacing reads from a spoke-provider instance
|
|
82
|
+
|
|
83
|
+
If your v1 code reached into a spoke provider for chain config or wallet info, those reads now have direct sources:
|
|
84
|
+
|
|
85
|
+
| v1 access | v2 source |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `provider.chainConfig.chain.name` | `baseChainInfo[chainKey].name` (from `@sodax/sdk`) |
|
|
88
|
+
| `provider.chainConfig.chain.type` | `getChainType(chainKey)` |
|
|
89
|
+
| `provider.walletProvider.getWalletAddress()` | The wallet provider you passed in — call `walletProvider.getWalletAddress()` directly. |
|
|
90
|
+
| `provider.publicClient` (EVM only) | If you absolutely need it: `sodax.hubProvider.publicClient` exists for hub-side reads. Spoke-side public clients aren't surfaced — use the typed read methods on each feature service instead. |
|
|
91
|
+
|
|
92
|
+
### Pitfall
|
|
93
|
+
|
|
94
|
+
If your project's v1 wrapper code instantiated `*SpokeProvider` classes, don't try to recreate that wrapper in v2 — it intentionally doesn't exist. Pass `walletProvider` directly into each SDK call payload.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 2. ConfigService replaces static lookups
|
|
99
|
+
|
|
100
|
+
### What's gone
|
|
101
|
+
|
|
102
|
+
| v1 global | v2 replacement |
|
|
103
|
+
|---|---|
|
|
104
|
+
| `hubAssets[chainId][address]` (vault lookup) | `token.vault` directly (added to `XToken` — see [`type-system.md`](type-system.md) § 4) |
|
|
105
|
+
| `hubAssets[chainId][address]` (hub-asset address) | `token.hubAsset` directly |
|
|
106
|
+
| `baseChainInfo[chain].id` | `baseChainInfo[chain].key` (field renamed) |
|
|
107
|
+
|
|
108
|
+
### Static defaults — still exported, prefer the service API
|
|
109
|
+
|
|
110
|
+
These v1 names still ship through `@sodax/sdk` (re-exported from `@sodax/types`), so a v1 `import { ... } from '@sodax/sdk'` will not break. Once you call `await sodax.config.initialize()`, the dynamic config from the backend supersedes the packaged defaults — read through the service API to see runtime updates (new tokens, fee parameters). Without `initialize()`, both paths return the same packaged values.
|
|
111
|
+
|
|
112
|
+
| v1 export | v2 status | Preferred v2 API |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `moneyMarketSupportedTokens[chainId]` | Still exported (`packages/types/src/moneyMarket/moneyMarket.ts`) | `sodax.moneyMarket.getSupportedTokensByChainId(chainKey)` |
|
|
115
|
+
| `Object.entries(moneyMarketSupportedTokens)` (walk pattern) | Const still exported | `sodax.moneyMarket.getSupportedTokens()` (returns `Record<SpokeChainKey, XToken[]>`) |
|
|
116
|
+
| `SodaTokens` registry (vault-validation) | Still exported (`packages/types/src/chains/tokens.ts`) | `sodax.config.getMoneyMarketReserveAssets()` or `sodax.moneyMarket.getSupportedReserves()` |
|
|
117
|
+
| `swapSupportedTokens[chainId]` (v1 had no `solverSupportedTokens`) | Still exported (`packages/types/src/swap/swap.ts`) | `sodax.config.getSupportedSwapTokensByChainId(chainKey)` |
|
|
118
|
+
|
|
119
|
+
### What replaces them
|
|
120
|
+
|
|
121
|
+
`ConfigService` is a stateful service owned by `Sodax`. It loads chain/token config from the backend API on `await sodax.config.initialize()` and falls back to packaged defaults from `@sodax/types` if the backend is unreachable. After init, every lookup goes through the service:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
const sodax = new Sodax(/* optional config override */);
|
|
125
|
+
await sodax.config.initialize(); // fetch from backend, fall back on failure
|
|
126
|
+
|
|
127
|
+
// Token lookups
|
|
128
|
+
const usdc = sodax.config.findSupportedTokenBySymbol(ChainKeys.ARBITRUM_MAINNET, 'USDC');
|
|
129
|
+
const supportedOnChain = sodax.config.getSupportedTokensPerChain();
|
|
130
|
+
|
|
131
|
+
// Hub-asset / vault lookups (when the XToken doesn't carry it)
|
|
132
|
+
const original = sodax.config.getOriginalAssetAddress(chainKey, hubAddress);
|
|
133
|
+
|
|
134
|
+
// Chain validity
|
|
135
|
+
const isValid = sodax.config.isValidSpokeChainKey(chainKey);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Feature services (`SwapService`, `MoneyMarketService`, …) receive `ConfigService` via constructor injection and use it internally — consumer-side code reads the same data through `sodax.config.*` or feature-specific wrappers like `sodax.moneyMarket.getSupportedTokens()`.
|
|
139
|
+
|
|
140
|
+
### Migration mechanics
|
|
141
|
+
|
|
142
|
+
```diff
|
|
143
|
+
- import { hubAssets, moneyMarketSupportedTokens } from '@sodax/types';
|
|
144
|
+
- const vault = hubAssets[chainId]?.[token.address]?.vault;
|
|
145
|
+
+ const vault = token.vault; // baked into XToken in v2
|
|
146
|
+
|
|
147
|
+
- const supplyTokens = moneyMarketSupportedTokens[chainId];
|
|
148
|
+
+ const supplyTokens = sodax.moneyMarket.getSupportedTokensByChainId(chainKey);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
If your code walked `hubAssets` to find "is this address a known vault?":
|
|
152
|
+
|
|
153
|
+
```diff
|
|
154
|
+
- const isKnownVault = !!hubAssets[chainId]?.[address];
|
|
155
|
+
+ const isKnownVault = sodax.config.getMoneyMarketReserveAssets()
|
|
156
|
+
+ .some(asset => asset.address === address);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Pitfall
|
|
160
|
+
|
|
161
|
+
The `swaps` config field changed semantics. v1 put solver endpoints under `SodaxConfig.swaps`. v2 has two fields:
|
|
162
|
+
|
|
163
|
+
- `SodaxConfig.swaps`: `SwapsConfig` listing supported solver tokens per chain (data, not endpoints).
|
|
164
|
+
- `SodaxConfig.solver`: `{ intentsContract, solverApiEndpoint, protocolIntentsContract }` (the endpoint/contract config that v1 misplaced under `swaps`).
|
|
165
|
+
|
|
166
|
+
If you pass a config override to `new Sodax({ ... })`, put solver endpoints in `solver`, not `swaps`.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 3. Relay flow and intent-relay reshape
|
|
171
|
+
|
|
172
|
+
### What changed
|
|
173
|
+
|
|
174
|
+
v1 had per-feature relay helpers (each feature module had its own `*WaitForRelay()` or `relay*Tx()` function). v2 centralises this into `IntentRelayApiService` with two public entry points:
|
|
175
|
+
|
|
176
|
+
- `submitTransaction({ srcChainKey, txHash, payload })` — POSTs the spoke transaction to the relay submit endpoint and resolves the relay's first-stage acknowledgement.
|
|
177
|
+
- `relayTxAndWaitPacket({ srcChainKey, dstChainKey, txHash, payload, timeout? })` — runs `submitTransaction` and then polls until the destination packet reaches `executed`. Resolves with `{ srcTxHash, dstTxHash, packet }` on success.
|
|
178
|
+
|
|
179
|
+
Internally, every feature service now calls `relayTxAndWaitPacket` for the spoke→hub leg. Failures from this layer surface to consumers via `mapRelayFailure`.
|
|
180
|
+
|
|
181
|
+
### `RELAY_ERROR_CODES` — the public relay-layer contract
|
|
182
|
+
|
|
183
|
+
The relay layer keeps a stable string vocabulary on its own errors (these are **not** `SodaxErrorCode` values — they are the lower-level relay codes that get mapped):
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
type RelayCode =
|
|
187
|
+
| 'SUBMIT_TX_FAILED'
|
|
188
|
+
| 'RELAY_TIMEOUT'
|
|
189
|
+
| 'RELAY_POLLING_FAILED'
|
|
190
|
+
| 'UNKNOWN';
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
When a relay-layer failure surfaces as a `SodaxError`, the original relay code lives on `error.context.relayCode`.
|
|
194
|
+
|
|
195
|
+
### `mapRelayFailure` — single shared mapper
|
|
196
|
+
|
|
197
|
+
v1 had five per-feature mappers (each feature reshaped relay errors into its own typed-error union). v2 collapses them into one:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { mapRelayFailure } from '@sodax/sdk';
|
|
201
|
+
|
|
202
|
+
const mapped = mapRelayFailure(error, {
|
|
203
|
+
feature: 'swap',
|
|
204
|
+
action: 'createIntent',
|
|
205
|
+
srcChainKey: ChainKeys.ARBITRUM_MAINNET,
|
|
206
|
+
dstChainKey: ChainKeys.STELLAR_MAINNET,
|
|
207
|
+
// phase: 'destinationExecution', // optional override; used by migration's bnUSD secondary watcher
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`mapped` is a `SodaxError<C>` with code in {`'TX_SUBMIT_FAILED'`, `'RELAY_TIMEOUT'`, `'RELAY_FAILED'`, `'EXECUTION_FAILED'`} and `feature` set to the requested value. Consumers don't usually call `mapRelayFailure` directly — every feature service does this internally — but it's exported for custom orchestration code.
|
|
212
|
+
|
|
213
|
+
### Migration mechanics for consumers
|
|
214
|
+
|
|
215
|
+
If your v1 code wrapped a feature call to handle relay failures:
|
|
216
|
+
|
|
217
|
+
```diff
|
|
218
|
+
- try {
|
|
219
|
+
- const tx = await sodax.swaps.createIntent({ intentParams, spokeProvider });
|
|
220
|
+
- } catch (e) {
|
|
221
|
+
- if (e instanceof RelayError && e.code === 'RELAY_TIMEOUT') { /* … */ }
|
|
222
|
+
- else if (e instanceof IntentError) { /* … */ }
|
|
223
|
+
- }
|
|
224
|
+
|
|
225
|
+
+ const result = await sodax.swaps.createIntent({ params, raw: false, walletProvider });
|
|
226
|
+
+ if (!result.ok) {
|
|
227
|
+
+ if (isSodaxError(result.error)) {
|
|
228
|
+
+ if (result.error.code === 'RELAY_TIMEOUT') { /* … */ }
|
|
229
|
+
+ else if (result.error.feature === 'swap' && result.error.code === 'INTENT_CREATION_FAILED') { /* … */ }
|
|
230
|
+
+ }
|
|
231
|
+
+ }
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The full v1 ↔ v2 code crosswalk is in [`result-and-errors.md`](result-and-errors.md) § "v1 ↔ v2 code crosswalk".
|
|
235
|
+
|
|
236
|
+
### Pitfall
|
|
237
|
+
|
|
238
|
+
`relayTxAndWaitPacket` is the public name; v1 had `submitTxAndWaitForPacket` and similar variants. If your v1 code imported or wrapped one of those names, the export is gone. Use `relayTxAndWaitPacket` directly, or call the feature service's higher-level method (`sodax.swaps.swap(...)`, `sodax.bridge.bridge(...)`) which wraps it.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 4. Invariants and guards
|
|
243
|
+
|
|
244
|
+
### What's gone
|
|
245
|
+
|
|
246
|
+
- Per-module typed error unions and their type-guards: `MoneyMarketError`, `IntentError`, `StakingError`, `BridgeError`, `MigrationError`, `AssetServiceError`, `ConcentratedLiquidityError`, `RelayError`, plus 5 partner error types and their `is<Module>Error()` helpers. (Structural deletion — see [`type-system.md`](type-system.md) § 10.)
|
|
247
|
+
- Ad-hoc precondition throws (`if (!x) throw new Error('Amount must be greater than 0')`).
|
|
248
|
+
|
|
249
|
+
### What replaces them
|
|
250
|
+
|
|
251
|
+
#### `sodaxInvariant` + per-feature aliases
|
|
252
|
+
|
|
253
|
+
Every feature has a 1-line alias for `sodaxInvariant` that pre-fills the `feature` field:
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
// Internal SDK helpers (also exported for custom code)
|
|
257
|
+
import {
|
|
258
|
+
sodaxInvariant,
|
|
259
|
+
swapInvariant,
|
|
260
|
+
mmInvariant,
|
|
261
|
+
bridgeInvariant,
|
|
262
|
+
stakingInvariant,
|
|
263
|
+
migrationInvariant,
|
|
264
|
+
dexInvariant,
|
|
265
|
+
partnerInvariant,
|
|
266
|
+
recoveryInvariant,
|
|
267
|
+
} from '@sodax/sdk';
|
|
268
|
+
|
|
269
|
+
mmInvariant(amount > 0n, 'Amount must be greater than 0');
|
|
270
|
+
// Throws SodaxError<'VALIDATION_FAILED'> with feature: 'moneyMarket' and the message above.
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
In your own consumer code, if you have your own preconditions, use `sodaxInvariant` directly (you pick the feature):
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
sodaxInvariant(
|
|
277
|
+
isValidSpokeChainKey(chainKey),
|
|
278
|
+
'Unsupported source chain',
|
|
279
|
+
{ feature: 'swap', context: { reason: 'unsupportedChain', srcChainKey: chainKey } },
|
|
280
|
+
);
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### `isSodaxError` and `isFeatureError`
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
import { isSodaxError, isFeatureError } from '@sodax/sdk';
|
|
287
|
+
|
|
288
|
+
if (isSodaxError(e)) {
|
|
289
|
+
// e: SodaxError<SodaxErrorCode>
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const isMmError = isFeatureError('moneyMarket');
|
|
293
|
+
if (isMmError(e)) {
|
|
294
|
+
// e: SodaxError<SodaxErrorCode> with feature: 'moneyMarket'
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
`isFeatureError` is a guard factory. Use it once at module top and then as a normal type guard:
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
const isSwapError = isFeatureError('swap');
|
|
302
|
+
const isStakingError = isFeatureError('staking');
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
#### `isCodeMember` for per-method narrowing
|
|
306
|
+
|
|
307
|
+
When a public method declares a narrow code union (e.g. `useSupplyError`), there's a corresponding `isUseSupplyError` guard you can apply to discriminate within a single feature:
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
// Inside per-feature errors.ts files (referenced by per-method types)
|
|
311
|
+
const SUPPLY_CODES: ReadonlySet<SupplyErrorCode> = new Set([
|
|
312
|
+
'VALIDATION_FAILED',
|
|
313
|
+
'INTENT_CREATION_FAILED',
|
|
314
|
+
'EXECUTION_FAILED',
|
|
315
|
+
'TX_VERIFICATION_FAILED',
|
|
316
|
+
'RELAY_TIMEOUT',
|
|
317
|
+
// …
|
|
318
|
+
]);
|
|
319
|
+
const isSupplyError = isCodeMember(SUPPLY_CODES);
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
You can build your own `isCodeMember(codes)` guards from `@sodax/sdk` exports.
|
|
323
|
+
|
|
324
|
+
### Pitfall
|
|
325
|
+
|
|
326
|
+
Don't try to recreate a typed-error union by aliasing `SodaxError` per feature — it defeats the design. The whole point of v2's error model is that one class with `(feature, code)` discrimination covers every case, and your switch statements use those two fields. If your v1 code had `try { … } catch (e: MoneyMarketError) { ... }`, replace the catch with `if (isSodaxError(e) && e.feature === 'moneyMarket')`.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
The two reference tables that used to live as Appendix A (deleted exports) and Appendix B (`SodaxConfig` reshape) have moved into `../reference/`:
|
|
332
|
+
|
|
333
|
+
- [`../reference/deleted-exports.md`](../reference/deleted-exports.md) — every v1 symbol removed from `@sodax/sdk` and `@sodax/types`, with its v2 replacement.
|
|
334
|
+
- [`../reference/sodax-config.md`](../reference/sodax-config.md) — `SodaxConfig` constructor reshape (`swaps` vs `solver`, `rpcConfig` keying, `hubProviderConfig` → `hubConfig`).
|
|
335
|
+
|
|
336
|
+
## Cross-references
|
|
337
|
+
|
|
338
|
+
- Type-level renames and shape changes: [`type-system.md`](type-system.md).
|
|
339
|
+
- Result/error model semantics: [`result-and-errors.md`](result-and-errors.md).
|
|
340
|
+
- v2 design context (architectural concepts): [`../../integration/architecture.md`](../../integration/architecture.md).
|
|
341
|
+
- ConfigService usage patterns: [`../../integration/recipes/`](../../integration/recipes/) § "Initialize Sodax".
|
|
342
|
+
- Public API surface: [`../../integration/reference/`](../../integration/reference/) § "Public API surface".
|