@sodax/sdk 2.0.0-rc.1 → 2.0.0-rc.3
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/ai-exported/AGENTS.md +1 -1
- package/ai-exported/integration/architecture.md +22 -8
- package/ai-exported/integration/quickstart.md +1 -1
- package/ai-exported/integration/recipes/initialize-sodax.md +25 -0
- package/ai-exported/migration/README.md +2 -2
- package/ai-exported/migration/breaking-changes/architecture.md +14 -5
- package/ai-exported/migration/breaking-changes/type-system.md +20 -0
- package/ai-exported/migration/checklist.md +9 -3
- package/ai-exported/migration/features/bridge.md +9 -6
- package/ai-exported/migration/recipes.md +68 -6
- package/ai-exported/migration/reference/deleted-exports.md +49 -22
- package/ai-exported/migration/reference/sodax-config.md +112 -19
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/ai-exported/AGENTS.md
CHANGED
|
@@ -63,7 +63,7 @@ ai-exported/
|
|
|
63
63
|
2. **Every async public method returns `Result<T>`.** Branch on `result.ok`. No throws across service boundaries. Sub-Result forwarding is the default: `if (!sub.ok) return sub`.
|
|
64
64
|
3. **Errors are `SodaxError<C>`.** A single class with a closed 13-code reason vocabulary (`VALIDATION_FAILED`, `RELAY_TIMEOUT`, `EXECUTION_FAILED`, …) plus a `feature` field (`'swap' | 'moneyMarket' | …`). The pair `(feature, code)` is your discriminator. Use `isSodaxError(e)` (not bare `instanceof`).
|
|
65
65
|
4. **Signed vs raw is a discriminated union.** `WalletProviderSlot<K, Raw>` enforces at compile time: `{ raw: false, walletProvider: <chain-narrowed> }` for signing, `{ raw: true }` for unsigned-tx building. Mixing them is a TypeScript error.
|
|
66
|
-
5. **Config is dynamic
|
|
66
|
+
5. **Config is dynamic; overrides only land on `sodax.config`.** Once a `Sodax` instance exists, always read via `sodax.config.*` (e.g. `sodax.config.spokeChainConfig[chainKey]`) — direct imports of `spokeChainConfig` / `sodaxConfig` from `@sodax/types` / `@sodax/sdk` are packaged-default snapshots and silently miss both `await sodax.config.initialize()` updates and `new Sodax(config)` overrides. Full instance-scope-reader table + module-scope rules: [`integration/recipes/initialize-sodax.md`](integration/recipes/initialize-sodax.md) § *Module-scope reads*. Per-symbol status of v1 globals: [`migration/breaking-changes/architecture.md`](migration/breaking-changes/architecture.md) § 2.
|
|
67
67
|
|
|
68
68
|
## Top 5 v1 → v2 traps
|
|
69
69
|
|
|
@@ -132,14 +132,20 @@ import { Sodax, type SodaxConfig, type DeepPartial } from '@sodax/sdk';
|
|
|
132
132
|
new Sodax(config?: DeepPartial<SodaxConfig>): Sodax;
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
-
`SodaxConfig`
|
|
135
|
+
`SodaxConfig` has exactly **10 fields** (all required at the type level, but `DeepPartial` makes every leaf optional):
|
|
136
136
|
|
|
137
|
-
- `
|
|
138
|
-
- `
|
|
139
|
-
- `
|
|
140
|
-
- `
|
|
141
|
-
- `
|
|
142
|
-
- `
|
|
137
|
+
- `fee: PartnerFee | undefined` — global partner fee, applied unless a feature-level config overrides.
|
|
138
|
+
- `chains: Record<SpokeChainKey, SpokeChainConfig>` — per-spoke-chain config. Each entry carries `rpcUrl`, polling config, and chain-family-specific extras (`BitcoinSpokeChainConfig`, `StellarSpokeChainConfig`, etc.).
|
|
139
|
+
- `swaps: SwapsConfig` — supported solver tokens per chain.
|
|
140
|
+
- `moneyMarket: MoneyMarketConfig` — money market contracts + supported tokens.
|
|
141
|
+
- `bridge: BridgeConfig` — bridge `{ partnerFee }` override.
|
|
142
|
+
- `dex: DexConfig` — DEX pool/asset config.
|
|
143
|
+
- `hub: HubConfig` — hub-chain (Sonic) full address map + RPC URL + polling config.
|
|
144
|
+
- `api: ApiConfig` — backend API endpoint (`{ baseURL, timeout, headers }`).
|
|
145
|
+
- `solver: SolverConfig` — `{ intentsContract, solverApiEndpoint, protocolIntentsContract }`.
|
|
146
|
+
- `relay: RelayConfig` — intent relay endpoint + chain-id map.
|
|
147
|
+
|
|
148
|
+
> **Not config slots** — `staking`, `migration`, `partner`/`partners`, `recovery` are services on the `Sodax` instance (`sodax.staking`, etc.) but they are **not** configurable via `SodaxConfig`. They run on packaged defaults; per-call params handle customization.
|
|
143
149
|
|
|
144
150
|
In production, the packaged defaults are sufficient — pass nothing and call `await sodax.config.initialize()` to load fresh data from the backend.
|
|
145
151
|
|
|
@@ -174,7 +180,15 @@ Chain configs (vault addresses, supported tokens, fee parameters) change between
|
|
|
174
180
|
|
|
175
181
|
### Custom backend
|
|
176
182
|
|
|
177
|
-
|
|
183
|
+
Point at a custom backend URL via `SodaxConfig.api.baseURL`:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
const sodax = new Sodax({
|
|
187
|
+
api: { baseURL: 'https://sandbox-api.example.com' },
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`SodaxConfig.api` is `ApiConfig` (`{ baseURL, timeout, headers }`) — pass any subset via `DeepPartial`. v2 does not provide a typed slot to inject a custom `IConfigApi` implementation at construction; if you need to mock the backend for tests, point `baseURL` at a local mock server, or construct your own `BackendApiService`-compatible mock and inject it where you control the `Sodax` instance (e.g. dependency-injected in your app layer).
|
|
178
192
|
|
|
179
193
|
---
|
|
180
194
|
|
|
@@ -196,7 +196,7 @@ The errors most likely to hit on a fresh install or first port.
|
|
|
196
196
|
|
|
197
197
|
### `sodax.config.initialize()` hangs / errors
|
|
198
198
|
|
|
199
|
-
- The backend API is unreachable. The SDK should fall back to packaged defaults silently — check your network, then check that `SodaxConfig.
|
|
199
|
+
- The backend API is unreachable. The SDK should fall back to packaged defaults silently — check your network, then check that `SodaxConfig.api.baseURL` is correct (or omit it for the default).
|
|
200
200
|
|
|
201
201
|
### Stellar bridge / swap fails with `'Trustline missing'`
|
|
202
202
|
|
|
@@ -45,6 +45,31 @@ await sodax.config.initialize();
|
|
|
45
45
|
|
|
46
46
|
`initialize()` is the only initialization step. Don't `await` it inside every feature call — call it once at app startup. If you skip it entirely, feature services fall back to packaged defaults, which may be stale relative to the latest backend config (new tokens, new chains, fee parameter changes).
|
|
47
47
|
|
|
48
|
+
## Module-scope reads (no Sodax instance needed)
|
|
49
|
+
|
|
50
|
+
Some code runs at **module-load time** — constants files, utility modules, framework-provider configs — before any `Sodax` instance exists. For those, import the packaged-default constants directly from `@sodax/sdk` (re-exported from `@sodax/types`):
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { sodaxConfig, hubConfig } from '@sodax/sdk';
|
|
54
|
+
|
|
55
|
+
// Hub address constants
|
|
56
|
+
export const HUB_WALLET = hubConfig.addresses.hubWallet;
|
|
57
|
+
export const STAKING_ROUTER = hubConfig.addresses.stakingRouter;
|
|
58
|
+
|
|
59
|
+
// Full default config (every SodaxConfig field with packaged defaults)
|
|
60
|
+
export const DEFAULT_SOLVER_ENDPOINT = sodaxConfig.solver.solverApiEndpoint;
|
|
61
|
+
export const SUPPORTED_TOKENS_PER_CHAIN = sodaxConfig.swaps.supportedTokens;
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
| Need | Module-scope import (defaults only) | Instance-scope read (with overrides) |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| Hub contract addresses (assetManager, hubWallet, stakingRouter, etc.) | `hubConfig.addresses.*` | `sodax.config.getHubChainConfig().addresses.*` |
|
|
67
|
+
| Full default SodaxConfig (read-only snapshot) | `sodaxConfig.*` (e.g. `sodaxConfig.hub`, `sodaxConfig.moneyMarket`) | `sodax.config.sodaxConfig` |
|
|
68
|
+
| Per-chain spoke config (rpcUrl, nativeToken, addresses, supportedTokens, polling) | `spokeChainConfig[ChainKeys.X_MAINNET]` (from `@sodax/types` / `@sodax/sdk`) | `sodax.config.spokeChainConfig[ChainKeys.X_MAINNET]` *or* `sodax.config.getChainConfig(ChainKeys.X_MAINNET)` |
|
|
69
|
+
| Money market reserve assets | `sodaxConfig.moneyMarket.supportedReserveAssets` | `sodax.config.getMoneyMarketReserveAssets()` |
|
|
70
|
+
|
|
71
|
+
> **Static vs dynamic — and the override-gap consequence.** `sodaxConfig` / `hubConfig` / `spokeChainConfig` are **packaged-default snapshots** frozen at SDK release time. They are safe at module scope but: (a) won't reflect backend-driven config updates loaded by `sodax.config.initialize()`, and (b) **won't reflect overrides passed to `new Sodax(config)`** — those merge into `sodax.config` (the `ConfigService`) but never mutate the static imports. So once a `Sodax` instance exists, prefer the instance-scope readers in the right column above — particularly `sodax.config.spokeChainConfig` over the same-named static import — or you will silently fall back to the packaged defaults for any chain you customized.
|
|
72
|
+
|
|
48
73
|
|
|
49
74
|
## Cross-references
|
|
50
75
|
|
|
@@ -10,7 +10,7 @@ v2 was a deep architectural reshape, not a feature release. Five orthogonal chan
|
|
|
10
10
|
2. **`Result<T>` everywhere.** Every async public method on every service returns `Promise<Result<T, SodaxError<C>>>`. v1 throw-on-error patterns are gone.
|
|
11
11
|
3. **One canonical error class.** `SodaxError<C>` with a closed 13-code vocabulary plus `feature: 'swap' | 'moneyMarket' | …`. The per-module typed error unions (`MoneyMarketError<Code>`, `IntentError<Code>`, `StakingError<Code>`, `BridgeError<Code>`, `MigrationError<Code>`, `AssetServiceError<Code>`, `ConcentratedLiquidityError<Code>`, partner errors, …) are deleted.
|
|
12
12
|
4. **`WalletProviderSlot<K, Raw>` is the discriminated union.** Every signed-execution method takes `{ raw: false, walletProvider }` (chain-narrowed via `GetWalletProviderType<K>`); every raw-tx-building method takes `{ raw: true }` (no wallet provider). Compile-time enforced.
|
|
13
|
-
5. **`ConfigService`
|
|
13
|
+
5. **`ConfigService` is the preferred lookup surface.** `hubAssets` and `*_MAINNET_CHAIN_ID` constants **are deleted** (won't compile). `moneyMarketSupportedTokens`, `SodaTokens`, `supportedSpokeChains` **are still exported** as packaged-default constants (so v1 imports keep compiling), but prefer `sodax.config.*` / `sodax.moneyMarket.getSupportedTokens*()` — those reflect backend-driven runtime updates after `await sodax.config.initialize()`. See [`breaking-changes/architecture.md`](breaking-changes/architecture.md) § 2 for the per-symbol table.
|
|
14
14
|
|
|
15
15
|
The remainder is per-feature (return shape diffs, field renames, new required params like `srcAddress`).
|
|
16
16
|
|
|
@@ -40,7 +40,7 @@ Same word, different concept across versions. Skim before reading the breaking-c
|
|
|
40
40
|
| **raw tx** | An ad-hoc method on each spoke provider, sometimes named `executeXxx`, returning a chain-specific payload. | The discriminator `{ raw: true }` on the standard SDK call shape. Return type narrows via `TxReturnType<K, true>` (`EvmRawTransaction`, `SolanaRawTransaction`, …). |
|
|
41
41
|
| **config** | A `SodaxConfig` object passed at construction with hard-coded chain/token tables. Solver endpoints lived under `SodaxConfig.swaps`. | A `Sodax` instance owns a `ConfigService` that loads from the backend API, with packaged defaults as fallback. `sodax.config.*` is the lookup surface. **Solver endpoints moved to `SodaxConfig.solver`** (not `swaps`); `swaps` is `SwapsConfig` (supported tokens). |
|
|
42
42
|
| **`xChainId` field on tokens** | Field name on the `Token` type. | Renamed: `XToken.chainKey`. Type also renamed: `Token` → `XToken`. |
|
|
43
|
-
| **`hubAssets` / `moneyMarketSupportedTokens`** | Static `Record` global maps imported and walked. |
|
|
43
|
+
| **`hubAssets` / `moneyMarketSupportedTokens`** | Static `Record` global maps imported and walked. | `hubAssets` **deleted** — won't compile. `moneyMarketSupportedTokens` **still exported** as a packaged default, but prefer `sodax.config.*` and `sodax.moneyMarket.getSupportedTokens*()` so backend updates take effect. Each `XToken` now carries `vault` and `hubAsset` directly. |
|
|
44
44
|
| **`SubmitSwapTxRequest.srcChainId`** | Numeric chain id field on the backend submit-swap request. | Renamed: `srcChainKey: SpokeChainKey`. |
|
|
45
45
|
| **`Intent.srcChain` / `Intent.dstChain`** | Read shape: `IntentRelayChainId` (bigint). | **Unchanged.** This is the relay chain id, not a spoke chain key. A blanket grep-replace `srcChain`→`srcChainKey` will break this. |
|
|
46
46
|
| **`AddressType`** | Bitcoin-specific address-type union. | Renamed: `BtcAddressType`. (Generic name freed up.) |
|
|
@@ -5,7 +5,7 @@ The structural changes that reshaped the SDK at the service / runtime layer. Rea
|
|
|
5
5
|
The four load-bearing shifts:
|
|
6
6
|
|
|
7
7
|
1. **Per-chain `*SpokeProvider` classes are deleted.** Routing is by chain key, dispatched internally by `SpokeService`.
|
|
8
|
-
2. **Static lookup tables
|
|
8
|
+
2. **Static lookup tables — `hubAssets` deleted; `moneyMarketSupportedTokens`, `SodaTokens`, `supportedSpokeChains` still exported as packaged defaults but should yield to `sodax.config.*` so backend updates take effect.** See § 2 below for the per-symbol status table.
|
|
9
9
|
3. **Relay flow is centralised.** Two functions (`relayTxAndWaitPacket`, `submitTransaction`) and one mapper (`mapRelayFailure`) replace per-feature relay helpers.
|
|
10
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
11
|
|
|
@@ -103,12 +103,21 @@ If your project's v1 wrapper code instantiated `*SpokeProvider` classes, don't t
|
|
|
103
103
|
|---|---|
|
|
104
104
|
| `hubAssets[chainId][address]` (vault lookup) | `token.vault` directly (added to `XToken` — see [`type-system.md`](type-system.md) § 4) |
|
|
105
105
|
| `hubAssets[chainId][address]` (hub-asset address) | `token.hubAsset` directly |
|
|
106
|
-
| `moneyMarketSupportedTokens[chainId]` | `sodax.moneyMarket.getSupportedTokensByChainId(chainKey)` |
|
|
107
|
-
| `Object.entries(moneyMarketSupportedTokens)` | `sodax.moneyMarket.getSupportedTokens()` (returns `Record<SpokeChainKey, XToken[]>`) |
|
|
108
|
-
| `SodaTokens` registry (vault-validation) | `sodax.config.getMoneyMarketReserveAssets()` or `sodax.moneyMarket.getSupportedReserves()` |
|
|
109
|
-
| `solverSupportedTokens[chainId]` | `sodax.config.getSupportedSwapTokensByChainId(chainKey)` |
|
|
110
106
|
| `baseChainInfo[chain].id` | `baseChainInfo[chain].key` (field renamed) |
|
|
111
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
|
+
| `getSupportedSolverTokens(chainId)` (free function) | Still exported (`packages/types/src/swap/swap.ts`) | `sodax.config.getSupportedSwapTokensByChainId(chainKey)` |
|
|
119
|
+
| `supportedSpokeChains` (`SpokeChainKey[]`) | Still exported (`packages/types/src/chains/chains.ts`) | `sodax.config.isValidSpokeChainKey(chainKey)` for validation, or read `sodaxConfig.chains` at module scope |
|
|
120
|
+
|
|
112
121
|
### What replaces them
|
|
113
122
|
|
|
114
123
|
`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:
|
|
@@ -194,6 +194,26 @@ v1 consumers reached into a global `hubAssets[chainId][address]` map to get the
|
|
|
194
194
|
|
|
195
195
|
Read shapes like `Intent` and `IntentResponse` from the backend keep `srcChain` / `dstChain` as the **relay** chain id (numeric, `IntentRelayChainId`). They are **not** chain keys and were **not** renamed to `srcChainKey`/`dstChainKey`. Only **request** types (`CreateIntentParams`, `CreateLimitOrderParams`, `SubmitSwapTxRequest`) gained the `*ChainKey` field names.
|
|
196
196
|
|
|
197
|
+
### Exception — partner module read shapes DID rename
|
|
198
|
+
|
|
199
|
+
The above "read shapes keep `srcChain`/`dstChain`" rule has one exception: **partner module** read shapes also renamed `dstChain` → `dstChainKey`. Specifically:
|
|
200
|
+
|
|
201
|
+
- `AutoSwapPreferences` (returned by `sodax.partners.getAutoSwapPreferences(queryAddress)`) — field `dstChain` → **`dstChainKey: SpokeChainKey | 'not configured'`**.
|
|
202
|
+
- `SetSwapPreferenceParams` (request type for `setSwapPreference`) — `dstChain` → `dstChainKey: SpokeChainKey`.
|
|
203
|
+
|
|
204
|
+
```diff
|
|
205
|
+
- // v1
|
|
206
|
+
- const prefs = await partnerFeeClaimService.getAutoSwapPreferences(addr);
|
|
207
|
+
- const destChain: SpokeChainId = prefs.dstChain;
|
|
208
|
+
|
|
209
|
+
+ // v2
|
|
210
|
+
+ const result = await sodax.partners.getAutoSwapPreferences(addr);
|
|
211
|
+
+ if (!result.ok) return;
|
|
212
|
+
+ const destChain: SpokeChainKey | 'not configured' = result.value.dstChainKey;
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
A blanket grep `dstChain` → `dstChainKey` is safe in the partner module **but** still unsafe in `Intent` / `IntentResponse` reads. Scope grep replacements per file or per import. The general rule for `srcChain` (Intent read field) is unchanged: it remains the relay chain id.
|
|
216
|
+
|
|
197
217
|
---
|
|
198
218
|
|
|
199
219
|
## 5. `RpcConfig` reshape
|
|
@@ -20,6 +20,11 @@ Work this top-down. Each step is independent enough to land as its own commit; t
|
|
|
20
20
|
[ ] 7. Add { raw: false } discriminator to every signed call shape that
|
|
21
21
|
previously took a positional spoke provider:
|
|
22
22
|
{ intentParams, spokeProvider } → { params, raw: false, walletProvider }
|
|
23
|
+
[ ] 7b. Cross-cutting rename: every payload field named `spokeProvider:` (incl.
|
|
24
|
+
approve/allowance/utility methods that aren't signed-execution shapes)
|
|
25
|
+
→ `walletProvider:`. Mechanical for the OBJECT-LITERAL field key; don't
|
|
26
|
+
blindly rename variable names of the same spelling. See
|
|
27
|
+
[`recipes.md`](recipes.md) § 1 "What's not safe to grep-replace".
|
|
23
28
|
[ ] 8. Add srcChainKey + srcAddress to every action params object that didn't
|
|
24
29
|
carry them in v1 (most MM, staking, dex, bridge, migration param shapes).
|
|
25
30
|
[ ] 9. Convert every await sodax.<service>.<method>(...) call site that previously
|
|
@@ -28,9 +33,10 @@ Work this top-down. Each step is independent enough to land as its own commit; t
|
|
|
28
33
|
[ ] 10. Delete imports of MoneyMarketError, IntentError, StakingError, BridgeError,
|
|
29
34
|
MigrationError, AssetServiceError, ConcentratedLiquidityError, RelayError,
|
|
30
35
|
plus the five Partner error types and their type-guard helpers.
|
|
31
|
-
[ ] 11. Replace any walked global lookup (hubAssets
|
|
32
|
-
|
|
33
|
-
sodax.
|
|
36
|
+
[ ] 11. Replace any walked global lookup (hubAssets, moneyMarketSupportedTokens,
|
|
37
|
+
SodaTokens, supportedSpokeChains) with the equivalent sodax.config.* /
|
|
38
|
+
sodax.moneyMarket.getSupportedTokens*() call. Per-symbol deleted-vs-
|
|
39
|
+
still-exported status: see breaking-changes/architecture.md § 2.
|
|
34
40
|
[ ] 12. Initialize ConfigService at app startup: await sodax.config.initialize().
|
|
35
41
|
Falls back to packaged defaults if the backend is unreachable.
|
|
36
42
|
[ ] 13. Add { raw: true } to any read-only allowance check that previously took
|
|
@@ -19,7 +19,7 @@ Pair: [`../../integration/features/bridge.md`](../../integration/features/bridge
|
|
|
19
19
|
|
|
20
20
|
| Type | v1 shape | v2 shape | Notes |
|
|
21
21
|
|---|---|---|---|
|
|
22
|
-
| `
|
|
22
|
+
| `CreateBridgeIntentParams` | `{ srcChainId, srcAsset, amount, dstChainId, dstAsset, recipient }` | `{ srcChainKey, srcAddress, srcToken, amount, dstChainKey, dstToken, recipient }` | Now generic `<K>`. Renames: `srcChainId`/`dstChainId` → `srcChainKey`/`dstChainKey`; `srcAsset`/`dstAsset` → `srcToken`/`dstToken`. `recipient` is **unchanged**. NEW required: `srcAddress` (user's spoke-side sender, distinct from `recipient` which is the destination receiver). |
|
|
23
23
|
| Bridge action wrapper | `{ params, spokeProvider }` | `{ params, raw: false, walletProvider }` | Same as every feature. |
|
|
24
24
|
| `bridge` return | `Promise<string>` (tx hash, throws on error) | `Promise<Result<TxHashPair, SodaxError>>` | Tx-pair + Result. |
|
|
25
25
|
| `getBridgeableAmount` | `Promise<bigint>` | `Promise<Result<BridgeLimit, SodaxError>>` where `BridgeLimit = { amount, decimals, type }` | Result-wrapped + richer return shape. Now takes `(from: XToken, to: XToken)` (was `(srcChainId, srcToken, dstChainId, dstToken)`). |
|
|
@@ -44,21 +44,24 @@ Pair: [`../../integration/features/bridge.md`](../../integration/features/bridge
|
|
|
44
44
|
|
|
45
45
|
```diff
|
|
46
46
|
- const txHash: string = await sodax.bridge.bridge({
|
|
47
|
-
- params: { srcAsset, amount, dstChainId,
|
|
47
|
+
- params: { srcAsset, amount, dstChainId, dstAsset, recipient },
|
|
48
48
|
- spokeProvider,
|
|
49
49
|
- });
|
|
50
50
|
+ const result = await sodax.bridge.bridge({
|
|
51
51
|
+ params: {
|
|
52
52
|
+ srcChainKey: ChainKeys.ARBITRUM_MAINNET,
|
|
53
|
-
+ srcAddress: '0x…',
|
|
54
|
-
+
|
|
53
|
+
+ srcAddress: '0x…', // NEW: required (your spoke-side sender)
|
|
54
|
+
+ srcToken, // RENAMED from `srcAsset`
|
|
55
|
+
+ amount,
|
|
55
56
|
+ dstChainKey: ChainKeys.STELLAR_MAINNET,
|
|
56
|
-
+
|
|
57
|
-
+
|
|
57
|
+
+ dstToken, // RENAMED from `dstAsset`
|
|
58
|
+
+ recipient: 'G…', // UNCHANGED — destination receiver
|
|
58
59
|
+ },
|
|
59
60
|
+ raw: false,
|
|
60
61
|
+ walletProvider,
|
|
61
62
|
+ });
|
|
63
|
+
+ // Type: Result<TxHashPair, BridgeOrchestrationError>
|
|
64
|
+
+ // where TxHashPair = { srcChainTxHash: string; dstChainTxHash: string }
|
|
62
65
|
+ if (!result.ok) return;
|
|
63
66
|
+ const { srcChainTxHash, dstChainTxHash } = result.value;
|
|
64
67
|
```
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# Migration recipes — v1 → v2
|
|
2
2
|
|
|
3
|
-
Practical patterns for porting consumer code without rewriting everything in one pass.
|
|
3
|
+
Practical patterns for porting consumer code without rewriting everything in one pass.
|
|
4
4
|
|
|
5
5
|
1. [Codemod patterns](#1-codemod-patterns) — regex find/replace + a small `ts-morph` script for the renames that grep can't safely handle.
|
|
6
|
-
2. [
|
|
7
|
-
3. [
|
|
6
|
+
2. [Free-function lookups at module scope](#2-free-function-lookups-at-module-scope) — `getHubChainConfig()` / `getMoneyMarketConfig()` migration for constants/util files where no `Sodax` instance exists yet.
|
|
7
|
+
3. [Error-shape adapter](#3-error-shape-adapter) — adapt v2 `SodaxError` onto v1 `{ code, data }` branches so existing error-formatting helpers keep working.
|
|
8
|
+
4. [Result adapter](#4-result-adapter) — wrap v2 `Result<T>` in a v1-style throw shim for incremental conversion of call sites.
|
|
8
9
|
|
|
9
10
|
These are migration-only — once the port is complete, delete them. They're not patterns for new code.
|
|
10
11
|
|
|
12
|
+
The patterns below describe **what** the rewrite needs to do; pick whichever codemod tool fits your project (regex, `ts-morph`, `jscodeshift`, IDE refactor). The example scripts use `ts-morph` for AST-level rewrites where regex is unsafe.
|
|
13
|
+
|
|
11
14
|
---
|
|
12
15
|
|
|
13
16
|
## 1. Codemod patterns
|
|
@@ -16,12 +19,27 @@ These are migration-only — once the port is complete, delete them. They're not
|
|
|
16
19
|
|
|
17
20
|
| Change | Find | Replace | Notes |
|
|
18
21
|
|---|---|---|---|
|
|
19
|
-
| Chain-id constants | `(\w+)_MAINNET_CHAIN_ID` | `ChainKeys.$1_MAINNET` | Mechanical.
|
|
22
|
+
| Chain-id constants | `(\w+)_MAINNET_CHAIN_ID` | `ChainKeys.$1_MAINNET` | Mechanical. **Two-pass — see below.** First-pass rewrites usages; second-pass fixes the broken `import { ... }` statements. |
|
|
20
23
|
| `xChainId` field on `XToken` | `\.xChainId\b` | `.chainKey` | Token field rename. Audit first — some non-token types may use `xChainId` differently. |
|
|
21
24
|
| `Token` type rename | `\bimport(.*)\bToken\b(.*)\bfrom 'sodax/types'` | `import$1XToken$2from '@sodax/sdk'` | Best done with `ts-morph` to avoid touching unrelated `Token` identifiers. |
|
|
22
25
|
| `SpokeChainId` → `SpokeChainKey` | `\b(SpokeChainId\|ChainId)\b` (in type positions) | `SpokeChainKey` | Audit — `ChainId` is also used by 3rd-party libs (viem, etc.). Limit to `@sodax/types` imports. |
|
|
23
26
|
| `AddressType` → `BtcAddressType` | `\bAddressType\b` (in `@sodax/types` import positions) | `BtcAddressType` | |
|
|
24
27
|
|
|
28
|
+
### Two-pass codemod for chain-id constants
|
|
29
|
+
|
|
30
|
+
A one-pass `_MAINNET_CHAIN_ID` → `ChainKeys.*_MAINNET` rewrite produces invalid syntax inside `import { ... }` blocks — `ChainKeys.SONIC_MAINNET` is a member-access expression, not a bare identifier, and cannot live inside a named-import list (TS1109).
|
|
31
|
+
|
|
32
|
+
Split the rewrite into two passes:
|
|
33
|
+
|
|
34
|
+
1. **Pass 1 — rewrite usages.** Every `<X>_MAINNET_CHAIN_ID` → `ChainKeys.<X>_MAINNET`. Touches expression positions and (incorrectly) named-import positions; the broken imports get fixed in pass 2.
|
|
35
|
+
2. **Pass 2 — sweep imports.** For each `import { … } from '@sodax/{types,sdk}'`, drop the now-broken `ChainKeys.<X>_MAINNET` entries from the named-imports list and ensure `ChainKeys` itself is imported once.
|
|
36
|
+
|
|
37
|
+
Use the `ts-morph` script from the chain-id section above as a starting point for an AST-aware version, or build the two passes with whatever tooling fits your repo. After pass 2, every chain-id reference compiles.
|
|
38
|
+
|
|
39
|
+
### Pitfall — duplicate `ChainKeys` imports
|
|
40
|
+
|
|
41
|
+
If a file imports `<X>_MAINNET_CHAIN_ID` from BOTH `@sodax/types` and `@sodax/sdk` (some legacy code split imports across the two), pass 2 may add `ChainKeys` to both import statements → `TS2300 Duplicate identifier 'ChainKeys'`. Either keep `ChainKeys` only in the first import block, or consolidate to one import — `@sodax/sdk` re-exports the entire `@sodax/types` surface, so a single `import … from '@sodax/sdk'` is sufficient.
|
|
42
|
+
|
|
25
43
|
### What's not safe to grep-replace
|
|
26
44
|
|
|
27
45
|
- `srcChain` → `srcChainKey` on **request** types only. Read shapes (`Intent.srcChain`, `IntentResponse.srcChain`) keep `srcChain` as the relay chain id. Use a `ts-morph` script keyed by parameter type.
|
|
@@ -95,7 +113,51 @@ The `ts-morph` script above edits in-place. Commit your tree before running.
|
|
|
95
113
|
|
|
96
114
|
---
|
|
97
115
|
|
|
98
|
-
## 2.
|
|
116
|
+
## 2. Free-function lookups at module scope
|
|
117
|
+
|
|
118
|
+
v1 exported free functions like `getHubChainConfig()` and `getMoneyMarketConfig(chainId)` that consumers called at **module-load time** inside constants/util files — *before* any `Sodax` instance exists. The v2 replacement on `Sodax.config.*` is unusable in that context (chicken-and-egg).
|
|
119
|
+
|
|
120
|
+
The real v2 answer: read directly from the packaged-default const `sodaxConfig`, re-exported from `@sodax/sdk` (and from `@sodax/types`):
|
|
121
|
+
|
|
122
|
+
| v1 free function | v2 module-scope equivalent |
|
|
123
|
+
|---|---|
|
|
124
|
+
| `getHubChainConfig()` | `sodaxConfig.hub` |
|
|
125
|
+
| `getMoneyMarketConfig(hubChainId)` | `sodaxConfig.moneyMarket` |
|
|
126
|
+
| `getMoneyMarketConfig(hubChainId).supportedTokens` | `sodaxConfig.moneyMarket.supportedTokens` |
|
|
127
|
+
| `getSolverConfig(SONIC_MAINNET_CHAIN_ID)` (read solver endpoints) | `sodaxConfig.solver` |
|
|
128
|
+
| (none — v1 had no module-scope-safe accessor for full hub object) | `sodaxConfig.hub.addresses.hubWallet`, `.assetManager`, etc. |
|
|
129
|
+
|
|
130
|
+
```diff
|
|
131
|
+
- // v1 — module-scope constants file (no Sodax instance available yet)
|
|
132
|
+
- import { getHubChainConfig, getMoneyMarketConfig } from '@sodax/sdk';
|
|
133
|
+
- import { SONIC_MAINNET_CHAIN_ID } from '@sodax/types';
|
|
134
|
+
-
|
|
135
|
+
- const hubConfig = { hubRpcUrl, chainConfig: getHubChainConfig() };
|
|
136
|
+
- const moneyMarketConfig = getMoneyMarketConfig(SONIC_MAINNET_CHAIN_ID);
|
|
137
|
+
|
|
138
|
+
+ // v2 — read from packaged defaults; no Sodax instance needed
|
|
139
|
+
+ import { sodaxConfig } from '@sodax/sdk';
|
|
140
|
+
+
|
|
141
|
+
+ const hubAddresses = sodaxConfig.hub.addresses;
|
|
142
|
+
+ const moneyMarketTokens = sodaxConfig.moneyMarket.supportedTokens;
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
> **Once you have a `Sodax` instance**, prefer `sodax.config.*` (`sodax.config.getHubChainConfig()`, `sodax.config.getMoneyMarketReserveAssets()`, etc.). The service-API path reflects backend-driven runtime updates after `await sodax.config.initialize()`; `sodaxConfig` is a packaged-default snapshot frozen at SDK release time.
|
|
146
|
+
|
|
147
|
+
For hub-only module-scope reads, `hubConfig` is also exported directly:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { hubConfig } from '@sodax/sdk';
|
|
151
|
+
|
|
152
|
+
const HUB_WALLET = hubConfig.addresses.hubWallet;
|
|
153
|
+
const STAKING_ROUTER = hubConfig.addresses.stakingRouter;
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
See [`reference/sodax-config.md`](reference/sodax-config.md) § "Pitfall — module-scope reads" for the same guidance in the SodaxConfig reshape doc.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 3. Error-shape adapter
|
|
99
161
|
|
|
100
162
|
If your consumer code has `getMmErrorText`, `getSwapErrorText`, or similar helpers that branch on a v1 error object's `.code` and `.data.error`, the minimal-change migration is to wrap incoming v2 `SodaxError` instances at the entry point of each helper:
|
|
101
163
|
|
|
@@ -191,7 +253,7 @@ See [`reference/error-code-crosswalk.md`](reference/error-code-crosswalk.md) for
|
|
|
191
253
|
|
|
192
254
|
---
|
|
193
255
|
|
|
194
|
-
##
|
|
256
|
+
## 4. Result adapter
|
|
195
257
|
|
|
196
258
|
If converting every call site to branch on `result.ok` in one pass isn't realistic, use a `throwIfError` shim during migration. Then convert call sites at your own pace.
|
|
197
259
|
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
# Deleted exports inventory
|
|
1
|
+
# Deleted / replaced exports inventory
|
|
2
2
|
|
|
3
|
-
Every v1 export
|
|
3
|
+
Every v1 export that's gone or repurposed in v2 — and its v2 successor. If you see `error TS2305: Module '"@sodax/sdk"' has no exported member '<X>'`, find `<X>` in the left column.
|
|
4
|
+
|
|
5
|
+
Two categories worth distinguishing:
|
|
6
|
+
- **Truly deleted** — the v1 symbol is gone; an import will fail compile (`TS2305`).
|
|
7
|
+
- **Name preserved, shape replaced** — a v1 `import` still compiles, but the runtime shape changed. Silent breakage if you read v1-only fields.
|
|
8
|
+
|
|
9
|
+
> Scope note: This doc only lists symbols that **don't import anymore** or **silently changed shape**. For v1 static constants that are still exported in v2 but should yield to the dynamic service API, see [`../breaking-changes/architecture.md`](../breaking-changes/architecture.md) § 2.
|
|
4
10
|
|
|
5
11
|
### Spoke-provider classes + guards
|
|
6
12
|
|
|
@@ -24,11 +30,9 @@ Every v1 export removed from `@sodax/sdk` and `@sodax/types`, with its v2 replac
|
|
|
24
30
|
| v1 export | v2 replacement |
|
|
25
31
|
|---|---|
|
|
26
32
|
| `hubAssets` | `XToken.vault` / `XToken.hubAsset` baked in; or `sodax.config.getOriginalAssetAddress(...)`. See [`../breaking-changes/architecture.md`](../breaking-changes/architecture.md) § 2. |
|
|
27
|
-
| `
|
|
28
|
-
| `solverSupportedTokens` | `sodax.config.getSupportedSwapTokensByChainId(chainKey)`. |
|
|
29
|
-
| `SodaTokens` | `sodax.config.getMoneyMarketReserveAssets()` / `sodax.moneyMarket.getSupportedReserves()`. |
|
|
30
|
-
| `getHubChainConfig()` | `sodax.config.*` lookups; specific chain configs are loaded by `ConfigService.initialize()`. |
|
|
33
|
+
| `getHubChainConfig()` (free function) | `sodax.config.getHubChainConfig()` (now a method on `ConfigService`, accessed via the `Sodax` instance). For module-scope reads (before a `Sodax` instance exists), see [`sodax-config.md`](sodax-config.md) § "Pitfall — module-scope reads". |
|
|
31
34
|
| `EvmWalletAbstraction` (class) | `sodax.hubProvider.getUserHubWalletAddress(...)` (the equivalent functionality lives on `EvmHubProvider`, accessed via the `Sodax` instance). |
|
|
35
|
+
| `HubService` (class) + `HubService.getUserHubWalletAddress(spokeAddress, spokeChainId, hubProvider)` (static method) | `sodax.hubProvider.getUserHubWalletAddress(spokeAddress, spokeChainKey)` (instance method on `EvmHubProvider`; doesn't take `hubProvider` arg — `this` is the hub provider). v1 callers in `dex/AssetService.ts`, `mm/useATokensBalances.ts`, `shared/useGetUserHubWalletAddress.ts` all flatten to this single shape. |
|
|
32
36
|
|
|
33
37
|
### Type aliases
|
|
34
38
|
|
|
@@ -38,10 +42,10 @@ Every v1 export removed from `@sodax/sdk` and `@sodax/types`, with its v2 replac
|
|
|
38
42
|
| `SpokeChainId` (type) | `SpokeChainKey`. |
|
|
39
43
|
| `EvmChainId` (type) | `EvmChainKey` (subset of `SpokeChainKey`). |
|
|
40
44
|
| `HubChainId` (type) | `HubChainKey` (literal `'sonic'`). |
|
|
41
|
-
| `Token` (type) | `XToken`.
|
|
42
|
-
| `AddressType` (type) | `BtcAddressType
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
| `Token` (type) | `XToken`. **Fully removed — no legacy alias.** `import type { Token } from '@sodax/types'` fails with `TS2305: '"@sodax/types"' has no exported member named 'Token'. Did you mean 'XToken'?`. The shape also changed (added `vault`, `hubAsset`; renamed `xChainId` → `chainKey`) — see [`../breaking-changes/type-system.md`](../breaking-changes/type-system.md) § 4. |
|
|
46
|
+
| `AddressType` (type — `'P2PKH' \| 'P2SH' \| 'P2WPKH' \| 'P2TR'`) | `BtcAddressType` (renamed; same shape). See [`../breaking-changes/type-system.md`](../breaking-changes/type-system.md) § 7. |
|
|
47
|
+
|
|
48
|
+
> Note: `BtcWalletAddressType` (`'taproot' | 'segwit'`, wallet-UI choice) is preserved in v2 with the same shape — it is **not** the same thing as `BtcAddressType` (on-chain address format). They coexist; do not blindly rename one to the other.
|
|
45
49
|
|
|
46
50
|
### Constants
|
|
47
51
|
|
|
@@ -53,24 +57,46 @@ Every v1 export removed from `@sodax/sdk` and `@sodax/types`, with its v2 replac
|
|
|
53
57
|
|
|
54
58
|
| v1 export | v2 replacement |
|
|
55
59
|
|---|---|
|
|
56
|
-
| `CustomProvider` (Hana-wallet window typedecl) |
|
|
60
|
+
| `CustomProvider` (Hana-wallet window typedecl) | **Pick by what you actually use:** (a) **You only declared `window.hanaWallet.ethereum: CustomProvider` for typedecl quietness, never called methods on it** → replace the type with `unknown` (`declare global { interface Window { hanaWallet: { ethereum: unknown } } }`). 1-line fix. (b) **You called `window.hanaWallet.ethereum.request(...)` or built a custom Hana wallet** → import the named helpers `requestAddress`, `requestSigning`, `requestJsonRpc` from `@sodax/sdk` and use them in place of the raw provider calls. These are the same low-level Hana-extension helpers v1 wrapped, now first-class exports. |
|
|
57
61
|
|
|
58
62
|
### Error types and guards
|
|
59
63
|
|
|
64
|
+
#### Error types — name preserved, shape replaced
|
|
65
|
+
|
|
66
|
+
The following v1 error types were **plain object literals** `{ code: T; data: GetXxxError<T> }`. v2 keeps the same export names but redefines them as type aliases for the canonical `SodaxError<NarrowCode>` class instance. **A v1 `import { MoneyMarketError } from '@sodax/sdk'` still compiles** — but reading `err.data` will silently fail at runtime because the v2 shape is `{ name, code, feature, message, stack, context, cause }`. Treat these as "shape replaced" rather than deleted.
|
|
67
|
+
|
|
68
|
+
| v1 shape | v2 shape | What to read |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| `MoneyMarketError<MoneyMarketErrorCode> = { code, data }` | `MoneyMarketError = SodaxError<MoneyMarketErrorCode>` (class instance) | `err.code`, `err.feature === 'moneyMarket'`, `err.context`, `err.cause`. See [`error-code-crosswalk.md`](error-code-crosswalk.md) for code crosswalk. |
|
|
71
|
+
| `BridgeError<BridgeErrorCode> = { code, data }` | `BridgeError = SodaxError<BridgeErrorCode>` | Same pattern; `err.feature === 'bridge'`. |
|
|
72
|
+
| `StakingError<StakingErrorCode> = { code, data }` | `StakingError = SodaxError<StakingErrorCode>` | Same pattern; `err.feature === 'staking'`. |
|
|
73
|
+
| `MigrationError<MigrationErrorCode> = { code, data }` | `MigrationError = SodaxError<MigrationErrorCode>` | Same pattern; `err.feature === 'migration'`. |
|
|
74
|
+
|
|
75
|
+
#### Error types — fully deleted
|
|
76
|
+
|
|
60
77
|
| v1 export | v2 replacement |
|
|
61
78
|
|---|---|
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
|
79
|
+
| `IntentError<IntentErrorCode>`, plus `IntentErrorCode`, `IntentErrorData` | `SwapError = SodaxError<SwapErrorCode>` (renamed). `feature: 'swap'`. |
|
|
80
|
+
| `AssetServiceError<AssetServiceErrorCode>`, plus the union | `DexError = SodaxError<DexErrorCode>`. `feature: 'dex'`. |
|
|
81
|
+
| `ConcentratedLiquidityError<ConcentratedLiquidityErrorCode>`, plus the union | `DexError = SodaxError<DexErrorCode>` (asset + CL collapsed into one feature). |
|
|
82
|
+
| `RelayError<RelayErrorCode>`, plus the union | `SodaxError<C>` with the lower-level relay code on `error.context.relayCode`. |
|
|
83
|
+
| `SetSwapPreferenceError`, `CreateIntentAutoSwapError`, `WaitIntentAutoSwapError`, `UnknownIntentAutoSwapError`, `ExecuteIntentAutoSwapError` (5 distinct partner error types in `PartnerFeeClaimService.ts`) | `PartnerError = SodaxError<PartnerErrorCode>`. `feature: 'partner'`. |
|
|
84
|
+
|
|
85
|
+
#### Type guards — deleted
|
|
86
|
+
|
|
87
|
+
v1 only exposed **specific per-failure-mode guards**. v2 deleted all of these and instead ships **feature-level guards** + helper builders (`isFeatureError('<feature>')`, `isCodeMember(codeSet)`).
|
|
88
|
+
|
|
89
|
+
| v1 deleted guard | v2 replacement |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `isIntentCreationFailedError(e)` | `isSwapCreateIntentError(e)` or `isSodaxError(e) && e.code === 'INTENT_CREATION_FAILED' && e.feature === 'swap'`. |
|
|
73
92
|
| `isIntentSubmitTxFailedError(e)` | `isSodaxError(e) && e.code === 'TX_SUBMIT_FAILED'`. |
|
|
93
|
+
| `isIntentPostExecutionFailedError(e)` | `isSodaxError(e) && e.feature === 'swap' && e.code === 'EXECUTION_FAILED' && e.context?.phase === 'postExecution'`. |
|
|
94
|
+
| `isWaitUntilIntentExecutedFailed(e)` | `isSodaxError(e) && e.feature === 'swap' && e.code === 'RELAY_TIMEOUT'`. The v1 guard fired when the destination packet never reached `executed`; in v2 that surfaces as the unified `RELAY_TIMEOUT` code (with the underlying relay code on `error.context.relayCode`). |
|
|
95
|
+
| `isIntentCreationUnknownError(e)` | `isSodaxError(e) && e.code === 'UNKNOWN' && e.feature === 'swap'`. |
|
|
96
|
+
| `isMoneyMarketSubmitTxFailedError`, `isMoneyMarketRelayTimeoutError`, `isMoneyMarketCreate{Supply,Borrow,Withdraw,Repay}IntentFailedError`, `isMoneyMarket{Supply,Borrow,Withdraw,Repay}UnknownError` (10 specific guards) | `isMoneyMarketError(e)` (new in v2) for the feature-level check, then narrow on `e.code` / `e.context.action`. |
|
|
97
|
+
| `isCreateIntentAutoSwapError`, `isWaitIntentAutoSwapError`, `isUnknownIntentAutoSwapError`, `isSetSwapPreferenceError` (4 partner guards) | `isPartnerError(e)` (new in v2) for the feature-level check, then narrow on `e.code` / `e.context.action`. |
|
|
98
|
+
|
|
99
|
+
> Note: `isMoneyMarketError`, `isBridgeError`, `isStakingError`, `isMigrationError`, `isSwapError`, `isDexError`, `isPartnerError`, `isRecoveryError` did **not** exist in v1 — v2 added them as new feature-level guards alongside `isSodaxError` and the `isFeatureError('<feature>')` factory. See [`../breaking-changes/result-and-errors.md`](../breaking-changes/result-and-errors.md) § 6 for migration patterns.
|
|
74
100
|
|
|
75
101
|
### Per-feature param shape
|
|
76
102
|
|
|
@@ -98,3 +124,4 @@ The [`error TS1360`](https://www.typescriptlang.org/docs/handbook/release-notes/
|
|
|
98
124
|
- [`README.md`](README.md) — migration reference index.
|
|
99
125
|
- [`../README.md`](../README.md) — migration overview.
|
|
100
126
|
- [`../checklist.md`](../checklist.md) — top-level migration checklist.
|
|
127
|
+
- [`../breaking-changes/architecture.md`](../breaking-changes/architecture.md) § 2 — guidance for v1 static constants that are still exported in v2.
|