@sodax/sdk 2.0.0-rc.2 → 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 +3 -1
- 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 +4 -3
- package/ai-exported/migration/reference/sodax-config.md +112 -19
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
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
|
|
|
@@ -115,6 +115,8 @@ These v1 names still ship through `@sodax/sdk` (re-exported from `@sodax/types`)
|
|
|
115
115
|
| `Object.entries(moneyMarketSupportedTokens)` (walk pattern) | Const still exported | `sodax.moneyMarket.getSupportedTokens()` (returns `Record<SpokeChainKey, XToken[]>`) |
|
|
116
116
|
| `SodaTokens` registry (vault-validation) | Still exported (`packages/types/src/chains/tokens.ts`) | `sodax.config.getMoneyMarketReserveAssets()` or `sodax.moneyMarket.getSupportedReserves()` |
|
|
117
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 |
|
|
118
120
|
|
|
119
121
|
### What replaces them
|
|
120
122
|
|
|
@@ -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
|
|
|
@@ -30,8 +30,9 @@ Two categories worth distinguishing:
|
|
|
30
30
|
| v1 export | v2 replacement |
|
|
31
31
|
|---|---|
|
|
32
32
|
| `hubAssets` | `XToken.vault` / `XToken.hubAsset` baked in; or `sodax.config.getOriginalAssetAddress(...)`. See [`../breaking-changes/architecture.md`](../breaking-changes/architecture.md) § 2. |
|
|
33
|
-
| `getHubChainConfig()` (free function) | `sodax.config.getHubChainConfig()` (now a method on `ConfigService`, accessed via the `Sodax` instance). |
|
|
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". |
|
|
34
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. |
|
|
35
36
|
|
|
36
37
|
### Type aliases
|
|
37
38
|
|
|
@@ -41,7 +42,7 @@ Two categories worth distinguishing:
|
|
|
41
42
|
| `SpokeChainId` (type) | `SpokeChainKey`. |
|
|
42
43
|
| `EvmChainId` (type) | `EvmChainKey` (subset of `SpokeChainKey`). |
|
|
43
44
|
| `HubChainId` (type) | `HubChainKey` (literal `'sonic'`). |
|
|
44
|
-
| `Token` (type) | `XToken`.
|
|
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. |
|
|
45
46
|
| `AddressType` (type — `'P2PKH' \| 'P2SH' \| 'P2WPKH' \| 'P2TR'`) | `BtcAddressType` (renamed; same shape). See [`../breaking-changes/type-system.md`](../breaking-changes/type-system.md) § 7. |
|
|
46
47
|
|
|
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.
|
|
@@ -56,7 +57,7 @@ Two categories worth distinguishing:
|
|
|
56
57
|
|
|
57
58
|
| v1 export | v2 replacement |
|
|
58
59
|
|---|---|
|
|
59
|
-
| `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. |
|
|
60
61
|
|
|
61
62
|
### Error types and guards
|
|
62
63
|
|
|
@@ -1,46 +1,137 @@
|
|
|
1
1
|
# `SodaxConfig` constructor reshape
|
|
2
2
|
|
|
3
|
-
The v2 `Sodax` constructor accepts a `DeepPartial<SodaxConfig>`. Several config fields renamed or
|
|
3
|
+
The v2 `Sodax` constructor accepts a `DeepPartial<SodaxConfig>`. Several config fields renamed, moved, or were added between v1 and v2; if your project passed a custom config, check these.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
## v2 `SodaxConfig` shape (source of truth)
|
|
6
|
+
|
|
7
|
+
Defined in `@sodax/types` (`packages/types/src/sodax-config/sodax-config.ts`):
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
type SodaxConfig = {
|
|
11
|
+
fee: PartnerFee | undefined; // global partner fee (overridable per-feature)
|
|
12
|
+
chains: Record<SpokeChainKey, SpokeChainConfig>; // per-spoke-chain config (rpcUrl + tx polling + chain-specific shape)
|
|
13
|
+
swaps: SwapsConfig; // supported swap tokens per chain
|
|
14
|
+
moneyMarket: MoneyMarketConfig; // money market service config
|
|
15
|
+
bridge: BridgeConfig; // bridge partner-fee override
|
|
16
|
+
dex: DexConfig; // DEX service config
|
|
17
|
+
hub: HubConfig; // hub-chain (Sonic) provider config
|
|
18
|
+
api: ApiConfig; // backend API endpoint
|
|
19
|
+
solver: SolverConfig; // intent solver endpoint + contracts
|
|
20
|
+
relay: RelayConfig; // intent-relay endpoint
|
|
21
|
+
};
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
A matching default `sodaxConfig` const is exported from the same module — `new Sodax()` deep-merges your `DeepPartial<SodaxConfig>` over it.
|
|
25
|
+
|
|
26
|
+
## v1 shape (for reference)
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// v1 — packages/sdk/src/shared/entities/Sodax.ts
|
|
30
|
+
type SodaxConfig = {
|
|
31
|
+
swaps?: SolverConfigParams; // { intentsContract, solverApiEndpoint, protocolIntentsContract?, partnerFee? }
|
|
32
|
+
moneyMarket?: MoneyMarketConfigParams;
|
|
33
|
+
migration?: MigrationServiceConfig;
|
|
34
|
+
bridge?: BridgeServiceConfig;
|
|
35
|
+
dex?: DexServiceConfig;
|
|
36
|
+
hubProviderConfig?: EvmHubProviderConfig; // { hubRpcUrl, chainConfig }
|
|
37
|
+
relayerApiEndpoint?: HttpUrl; // single URL string
|
|
38
|
+
backendApiConfig?: BackendApiConfig;
|
|
39
|
+
partners?: PartnerServiceConfig;
|
|
40
|
+
sharedConfig?: typeof defaultSharedConfig;
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
All v1 fields were **optional**. v1 had **no** top-level `rpcConfig` on `SodaxConfig` — RPC URLs were a separate prop accepted by the framework-layer `SodaxProvider` (alongside the `config` prop carrying `SodaxConfig`); the `Sodax` class constructor itself never received `rpcConfig`.
|
|
45
|
+
|
|
46
|
+
## v1 → v2 field map
|
|
47
|
+
|
|
48
|
+
| v1 location | v2 location | Notes |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `SodaxConfig.swaps` (`SolverConfigParams` — `{ intentsContract, solverApiEndpoint, protocolIntentsContract?, partnerFee? }`) | **Split into two:** `SodaxConfig.solver: SolverConfig` (`{ intentsContract, solverApiEndpoint, protocolIntentsContract }`) and `SodaxConfig.swaps: SwapsConfig` (supported tokens per chain — new in v2). | v1 partner-fee inside `SolverConfigParams` moves to the global `SodaxConfig.fee` slot or per-feature configs. |
|
|
51
|
+
| `SodaxConfig.hubProviderConfig` (`EvmHubProviderConfig` — `{ hubRpcUrl, chainConfig }`) | **`SodaxConfig.hub`** (`HubConfig` — full hub addresses + native token + bnUSD + polling + RPC URL). | Field renamed `hubProviderConfig` → `hub`. Shape expanded: v1 just had RPC URL + chain config; v2 ships the full hub-contract address map. |
|
|
52
|
+
| `SodaxConfig.moneyMarket` (`MoneyMarketConfigParams`) | `SodaxConfig.moneyMarket` (`MoneyMarketConfig` — required, shape changed). | Reshape, see `@sodax/types/src/common/common.ts` MoneyMarketConfig. |
|
|
53
|
+
| `SodaxConfig.bridge` (`BridgeServiceConfig`) | `SodaxConfig.bridge` (`BridgeConfig` — `{ partnerFee }`). | Reshape; smaller. |
|
|
54
|
+
| `SodaxConfig.dex` (`DexServiceConfig`) | `SodaxConfig.dex` (`DexConfig`). | Reshape. |
|
|
55
|
+
| `SodaxConfig.relayerApiEndpoint: HttpUrl` (string) | **`SodaxConfig.relay`** (`RelayConfig` — object with relayer URL + chain-id map). | Renamed + reshaped from string to object. |
|
|
56
|
+
| `SodaxConfig.backendApiConfig` (`BackendApiConfig`) | **`SodaxConfig.api`** (`ApiConfig`). | Renamed. |
|
|
57
|
+
| (Separate `rpcConfig` prop on the framework-layer SodaxProvider, NOT a `SodaxConfig` field) | **`SodaxConfig.chains`** (`Record<SpokeChainKey, SpokeChainConfig>`). | v2 absorbs RPC URLs + polling + chain-specific extras into the `SodaxConfig.chains` mapped type. v1's separate `rpcConfig` provider prop is gone. The standalone `RpcConfig` type still ships from `@sodax/types` for utility use (e.g. the demo's `providers.tsx` declares a local `RpcConfig` then maps values into `chains`), but it is not a `SodaxConfig` field. |
|
|
58
|
+
| `SodaxConfig.migration` (`MigrationServiceConfig`) | **Removed.** Migration service runs with hard-coded defaults. | No replacement on `SodaxConfig`. v2 surfaces customization via per-method params on `sodax.migration.*`, not constructor config — see [`../features/icx-bnusd-baln.md`](../features/icx-bnusd-baln.md). |
|
|
59
|
+
| `SodaxConfig.partners` (`PartnerServiceConfig`) | **Removed.** Partner service runs with defaults. | Per-claim partner-fee config now flows via call-level params on `sodax.partners.*` methods. |
|
|
60
|
+
| `SodaxConfig.sharedConfig` (`typeof defaultSharedConfig`) | **Removed.** | Absorbed into `ConfigService` + per-chain `SpokeChainConfig`. Override individual chains via `SodaxConfig.chains[key]`. |
|
|
61
|
+
| (none in v1) | **`SodaxConfig.fee: PartnerFee \| undefined`** (new). | Global partner-fee, applies to all features unless overridden by feature-level config (`bridge.partnerFee`, money market, etc.). |
|
|
62
|
+
| (v1 had no top-level `configService` injection slot on `SodaxConfig` — `ConfigService` was always constructed internally from `backendApiConfig` + `sharedConfig`.) | Same — `ConfigService` is internal. v2 does **not** expose a typed slot to inject a custom `IConfigApi` either. To swap the backend in tests, point `SodaxConfig.api.baseURL` at a mock server. | See Pitfall below. |
|
|
11
63
|
|
|
12
64
|
Migration:
|
|
13
65
|
|
|
14
66
|
```diff
|
|
15
|
-
|
|
67
|
+
- // v1 — typical SodaxConfig literal
|
|
68
|
+
- const sodaxConfig = {
|
|
69
|
+
- hubProviderConfig: { hubRpcUrl: 'https://…', chainConfig: getHubChainConfig() },
|
|
70
|
+
- moneyMarket: getMoneyMarketConfig(hubChainId),
|
|
16
71
|
- swaps: {
|
|
17
72
|
- intentsContract: '0x…',
|
|
18
73
|
- solverApiEndpoint: 'https://…',
|
|
19
|
-
-
|
|
74
|
+
- protocolIntentsContract: '0x…',
|
|
75
|
+
- partnerFee: { address: '0x…', percentage: 10 },
|
|
20
76
|
- },
|
|
77
|
+
- relayerApiEndpoint: 'https://relay.example.com',
|
|
78
|
+
- } satisfies SodaxConfig;
|
|
79
|
+
- // RPC URLs were passed as a SEPARATE prop on the framework-layer SodaxProvider
|
|
80
|
+
- // (alongside the sodaxConfig). The Sodax constructor itself never saw rpcConfig.
|
|
81
|
+
|
|
82
|
+
+ // v2 — DeepPartial<SodaxConfig> passed directly to new Sodax(...)
|
|
83
|
+
+ const sodax = new Sodax({
|
|
84
|
+
+ hub: { /* HubConfig — usually omit, default ships full hub addresses */ },
|
|
21
85
|
+ solver: {
|
|
22
86
|
+ intentsContract: '0x…',
|
|
23
87
|
+ solverApiEndpoint: 'https://…',
|
|
88
|
+
+ protocolIntentsContract: '0x…',
|
|
24
89
|
+ },
|
|
25
90
|
+ swaps: {
|
|
26
91
|
+ supportedTokens: { /* per-chain table */ },
|
|
27
92
|
+ },
|
|
28
|
-
|
|
29
|
-
+
|
|
30
|
-
+
|
|
31
|
-
+ [ChainKeys.
|
|
32
|
-
+ [ChainKeys.
|
|
93
|
+
+ relay: { /* RelayConfig — relayer URL + chain-id map */ },
|
|
94
|
+
+ fee: { address: '0x…', percentage: 10 }, // global partner fee (moved out of swaps)
|
|
95
|
+
+ chains: {
|
|
96
|
+
+ [ChainKeys.SONIC_MAINNET]: { rpcUrl: 'https://…' },
|
|
97
|
+
+ [ChainKeys.ARBITRUM_MAINNET]: { rpcUrl: 'https://…' },
|
|
98
|
+
+ [ChainKeys.BITCOIN_MAINNET]: { /* BitcoinSpokeChainConfig shape */ },
|
|
33
99
|
+ // …
|
|
34
100
|
+ },
|
|
35
|
-
|
|
36
|
-
+
|
|
37
|
-
});
|
|
38
|
-
await sodax.config.initialize();
|
|
101
|
+
+ });
|
|
102
|
+
+ await sodax.config.initialize();
|
|
39
103
|
```
|
|
40
104
|
|
|
105
|
+
## Per-chain `SpokeChainConfig` shape
|
|
106
|
+
|
|
107
|
+
`SodaxConfig.chains` is keyed by `SpokeChainKey`; each entry's value type varies by chain family. The user-overridable surface (`rpcUrl`, polling config, chain-specific extras) is the same set of fields `RpcConfig` covers in v1, but nested inside `SpokeChainConfig` rather than flat. Inspect the type at:
|
|
108
|
+
|
|
109
|
+
- `packages/types/src/chains/chains.ts` — `SpokeChainConfig` discriminated union
|
|
110
|
+
- `packages/types/src/common/common.ts` — `BitcoinRpcConfig`, `StellarRpcConfig`, `InjectiveRpcConfig` (used inside the EVM-non-EVM branches)
|
|
111
|
+
|
|
112
|
+
See [`../breaking-changes/type-system.md`](../breaking-changes/type-system.md) § 5 for the chain-family-specific entry shapes.
|
|
113
|
+
|
|
41
114
|
### Pitfall
|
|
42
115
|
|
|
43
|
-
If you previously injected a custom `ConfigService` for testing (a v1 escape hatch), v2 doesn't accept one at the top level
|
|
116
|
+
If you previously injected a custom `ConfigService` for testing (a v1 escape hatch), v2 doesn't accept one at the top level — and unlike what earlier doc versions claimed, **v2 also doesn't expose a typed slot to inject a custom `IConfigApi`**. The realistic options:
|
|
117
|
+
|
|
118
|
+
- Point `SodaxConfig.api.baseURL` at a local mock backend server.
|
|
119
|
+
- Construct your own `BackendApiService`-compatible object in your app/test bootstrap and swap it in where you control the `Sodax` instance.
|
|
120
|
+
|
|
121
|
+
The `SodaxConfig.api` field is `ApiConfig` (`{ baseURL, timeout, headers }`) — there is no `api.api` sub-field for IConfigApi injection.
|
|
122
|
+
|
|
123
|
+
### Pitfall — module-scope reads
|
|
124
|
+
|
|
125
|
+
If your code reads hub addresses or default configs **before** the `Sodax` instance exists (module-scope constants), use the re-exported defaults from `@sodax/types` (also flow through `@sodax/sdk` since it re-exports the entire types surface):
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { hubConfig, sodaxConfig } from '@sodax/sdk';
|
|
129
|
+
|
|
130
|
+
const HUB_WALLET = hubConfig.addresses.hubWallet; // module-scope OK
|
|
131
|
+
const DEFAULT_RELAY = sodaxConfig.relay; // module-scope OK
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`hubConfig` / `sodaxConfig` are the **packaged defaults** — the same values `ConfigService` falls back to if the backend is unreachable. Once you have a `Sodax` instance, prefer `sodax.config.getHubChainConfig()` / `sodax.config.*` so backend-driven updates take effect.
|
|
44
135
|
|
|
45
136
|
---
|
|
46
137
|
|
|
@@ -50,3 +141,5 @@ If you previously injected a custom `ConfigService` for testing (a v1 escape hat
|
|
|
50
141
|
- [`README.md`](README.md) — migration reference index.
|
|
51
142
|
- [`../README.md`](../README.md) — migration overview.
|
|
52
143
|
- [`../checklist.md`](../checklist.md) — top-level migration checklist.
|
|
144
|
+
- [`../breaking-changes/type-system.md`](../breaking-changes/type-system.md) § 5 — per-chain config entry shapes.
|
|
145
|
+
- [`deleted-exports.md`](deleted-exports.md) — `getHubChainConfig()` and other deleted symbols.
|
package/dist/index.cjs
CHANGED
|
@@ -3899,7 +3899,7 @@ function isValidWalletProviderForChainKey(chainKey, walletProvider) {
|
|
|
3899
3899
|
}
|
|
3900
3900
|
|
|
3901
3901
|
// ../types/dist/index.js
|
|
3902
|
-
var CONFIG_VERSION =
|
|
3902
|
+
var CONFIG_VERSION = 201;
|
|
3903
3903
|
function isEvmSpokeChainConfig(value) {
|
|
3904
3904
|
return typeof value === "object" && value !== null && value.chain.type === "EVM" && value.chain.key !== HUB_CHAIN_KEY;
|
|
3905
3905
|
}
|