@sodax/sdk 1.5.6-beta → 2.0.0-rc.1
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 +335 -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 +100 -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 +32154 -31601
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8442 -6974
- package/dist/index.d.ts +8442 -6974
- package/dist/index.mjs +32642 -32130
- package/dist/index.mjs.map +1 -1
- package/package.json +19 -11
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# v1 → v2 cross-cutting migration checklist
|
|
2
|
+
|
|
3
|
+
Work this top-down. Each step is independent enough to land as its own commit; the order minimizes typecheck noise.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
[ ] 1. Replace every *_MAINNET_CHAIN_ID constant with ChainKeys.* (mechanical).
|
|
7
|
+
See breaking-changes/type-system.md § "Chain IDs".
|
|
8
|
+
[ ] 2. Replace every SpokeChainId / ChainId type alias with SpokeChainKey.
|
|
9
|
+
Mechanical rename. Same value union.
|
|
10
|
+
[ ] 3. Rename XToken.xChainId → XToken.chainKey. Same for any consumer types
|
|
11
|
+
that mirrored that field.
|
|
12
|
+
[ ] 4. Remove any direct dependency on @sodax/types from package.json.
|
|
13
|
+
v2 @sodax/sdk barrel re-exports the entire types surface.
|
|
14
|
+
[ ] 5. Delete every *SpokeProvider class instantiation. Replace with passing
|
|
15
|
+
walletProvider (an I*WalletProvider instance) directly into SDK call
|
|
16
|
+
payloads.
|
|
17
|
+
[ ] 6. Replace every isXxxSpokeProvider(provider) guard with a chain-key
|
|
18
|
+
compare: chainKey === ChainKeys.<X>_MAINNET, or use
|
|
19
|
+
is<Family>ChainKeyType(chainKey) from @sodax/sdk.
|
|
20
|
+
[ ] 7. Add { raw: false } discriminator to every signed call shape that
|
|
21
|
+
previously took a positional spoke provider:
|
|
22
|
+
{ intentParams, spokeProvider } → { params, raw: false, walletProvider }
|
|
23
|
+
[ ] 8. Add srcChainKey + srcAddress to every action params object that didn't
|
|
24
|
+
carry them in v1 (most MM, staking, dex, bridge, migration param shapes).
|
|
25
|
+
[ ] 9. Convert every await sodax.<service>.<method>(...) call site that previously
|
|
26
|
+
threw to branch on result.ok / result.error. Use isSodaxError(e) for type
|
|
27
|
+
narrowing.
|
|
28
|
+
[ ] 10. Delete imports of MoneyMarketError, IntentError, StakingError, BridgeError,
|
|
29
|
+
MigrationError, AssetServiceError, ConcentratedLiquidityError, RelayError,
|
|
30
|
+
plus the five Partner error types and their type-guard helpers.
|
|
31
|
+
[ ] 11. Replace any walked global lookup (hubAssets[chainId][address],
|
|
32
|
+
moneyMarketSupportedTokens[chainId], SodaTokens[...]) with the equivalent
|
|
33
|
+
sodax.config.* / sodax.moneyMarket.getSupportedTokens*() calls.
|
|
34
|
+
[ ] 12. Initialize ConfigService at app startup: await sodax.config.initialize().
|
|
35
|
+
Falls back to packaged defaults if the backend is unreachable.
|
|
36
|
+
[ ] 13. Add { raw: true } to any read-only allowance check that previously took
|
|
37
|
+
a spoke provider but didn't actually consult it (the underlying SDK
|
|
38
|
+
method now requires WalletProviderSlot).
|
|
39
|
+
[ ] 14. For every CreateIntentResult consumer: stop destructuring as a tuple;
|
|
40
|
+
the v2 shape is { tx, intent, relayData }. Stop destructuring tx-pair
|
|
41
|
+
results as arrays — every cross-chain mutation returns
|
|
42
|
+
TxHashPair = { srcChainTxHash, dstChainTxHash }.
|
|
43
|
+
[ ] 15. For every backend-API call site: every method on IConfigApi now returns
|
|
44
|
+
Promise<Result<T>>. Wrap or unwrap accordingly.
|
|
45
|
+
[ ] 16. (Optional) Adopt isSodaxError(e) over instanceof SodaxError in cross-bundle
|
|
46
|
+
/ cross-realm contexts.
|
|
47
|
+
[ ] 17. Run pnpm tsc --noEmit and start crossing items off the typecheck output.
|
|
48
|
+
Use each remaining error category to navigate to the relevant per-feature
|
|
49
|
+
migration file in features/.
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
After items 1–17 land, the typecheck should be clean. The remaining work is per-feature behavior (cross-chain borrow / repay deltas, staking action discriminators, etc.) covered in [`features/`](features/).
|
|
53
|
+
|
|
54
|
+
## Reading order while working the checklist
|
|
55
|
+
|
|
56
|
+
- Items 1–4: [`breaking-changes/type-system.md`](breaking-changes/type-system.md).
|
|
57
|
+
- Items 5–6, 11–12: [`breaking-changes/architecture.md`](breaking-changes/architecture.md).
|
|
58
|
+
- Items 7–8, 13: [`breaking-changes/architecture.md`](breaking-changes/architecture.md) § "WalletProviderSlot" + per-feature files.
|
|
59
|
+
- Items 9–10, 14, 16: [`breaking-changes/result-and-errors.md`](breaking-changes/result-and-errors.md).
|
|
60
|
+
- Item 15: [`features/auxiliary-services.md`](features/auxiliary-services.md) § "BackendApiService".
|
|
61
|
+
- Item 17 + the long tail: [`features/`](features/), one per feature you use.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Per-feature migration playbooks — v1 → v2
|
|
2
|
+
|
|
3
|
+
One file per feature, paired with the v2 design counterpart in [`../../integration/features/`](../../integration/features/) (same filename).
|
|
4
|
+
|
|
5
|
+
| Feature | Migration file |
|
|
6
|
+
|---|---|
|
|
7
|
+
| Swap | [`swap.md`](swap.md) |
|
|
8
|
+
| Money Market | [`money-market.md`](money-market.md) |
|
|
9
|
+
| Staking | [`staking.md`](staking.md) |
|
|
10
|
+
| Bridge | [`bridge.md`](bridge.md) |
|
|
11
|
+
| DEX | [`dex.md`](dex.md) |
|
|
12
|
+
| ICX/bnUSD/BALN | [`icx-bnusd-baln.md`](icx-bnusd-baln.md) |
|
|
13
|
+
| Auxiliary services | [`auxiliary-services.md`](auxiliary-services.md) — `PartnerService` + `RecoveryService` + `BackendApiService`. The backend-API one is the load-bearing change: every method now returns `Promise<Result<T>>`. |
|
|
14
|
+
|
|
15
|
+
## Reading order within a feature
|
|
16
|
+
|
|
17
|
+
Each per-feature file follows the same shape:
|
|
18
|
+
|
|
19
|
+
1. **TL;DR** — the load-bearing changes in 5–10 bullets.
|
|
20
|
+
2. **Type / symbol cheat sheet** — exact renames and shape diffs.
|
|
21
|
+
3. **Per-method delta** — call shape v1 vs v2, return type v1 vs v2, error model v1 vs v2.
|
|
22
|
+
4. **Worked example** — a representative migration of one call site, before / after.
|
|
23
|
+
5. **Pitfalls** — the things that look right but compile or run wrong.
|
|
24
|
+
6. **Verification** — what to run to confirm the port is complete.
|
|
25
|
+
|
|
26
|
+
## Cross-cutting prerequisites
|
|
27
|
+
|
|
28
|
+
Before reading any feature file, finish the cross-cutting work in:
|
|
29
|
+
|
|
30
|
+
- [`../README.md`](../README.md) — top-level checklist (chain-id rename, type renames, `walletProvider` extraction).
|
|
31
|
+
- [`../breaking-changes/type-system.md`](../breaking-changes/type-system.md) — type imports must compile first.
|
|
32
|
+
- [`../breaking-changes/architecture.md`](../breaking-changes/architecture.md) — `*SpokeProvider` deletion, `ConfigService`.
|
|
33
|
+
- [`../breaking-changes/result-and-errors.md`](../breaking-changes/result-and-errors.md) — `Result<T>` and `SodaxError<C>`.
|
|
34
|
+
|
|
35
|
+
Per-feature work assumes those are done.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Auxiliary services migration — v1 → v2
|
|
2
|
+
|
|
3
|
+
Pure-SDK migration playbook for `PartnerService`, `RecoveryService`, and `BackendApiService`. Three small services grouped because each has a small surface area.
|
|
4
|
+
|
|
5
|
+
Pair: [`../../integration/features/auxiliary-services.md`](../../integration/features/auxiliary-services.md).
|
|
6
|
+
|
|
7
|
+
## TL;DR
|
|
8
|
+
|
|
9
|
+
1. **`PartnerService`:** standard pattern. Drop `spokeProvider`; pass `walletProvider`. Add `srcChainKey` + `srcAddress` to claim params. v1's 5 typed errors collapse into `SodaxError<C>` with `feature: 'partner'`.
|
|
10
|
+
2. **`RecoveryService`:** **new in v2.** No v1 equivalent — there's no migration to do for code that didn't exist before. Just integration: see [`../../integration/features/auxiliary-services.md`](../../integration/features/auxiliary-services.md).
|
|
11
|
+
3. **`BackendApiService`:** the load-bearing change. **Every method now returns `Promise<Result<T>>`** (v1 returned plain `Promise<T>` and threw on failure). `IConfigApi` implementations must update method signatures.
|
|
12
|
+
4. **`SubmitSwapTxRequest.srcChainId` → `srcChainKey`.** And `relayData` field is `string` (`relayData.payload`), not the `RelayExtraData` object. (Cross-cutting detail; covered in detail in [`swap.md`](swap.md).)
|
|
13
|
+
|
|
14
|
+
## `PartnerService`
|
|
15
|
+
|
|
16
|
+
### Type / symbol cheat sheet
|
|
17
|
+
|
|
18
|
+
| Type | v1 shape | v2 shape | Notes |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| Partner action params | non-generic | now generic `<K>` with `srcChainKey`, `srcAddress` | |
|
|
21
|
+
| Partner errors (5 types) | `PartnerFeeClaimError<...>` and 4 siblings | `SodaxError<C>` with `feature: 'partner'` | All 5 v1 typed errors collapse. |
|
|
22
|
+
|
|
23
|
+
### v1 → v2 error code crosswalk
|
|
24
|
+
|
|
25
|
+
All 5 v1 partner error codes map to `EXECUTION_FAILED` with `error.context.action` discriminating between the operations.
|
|
26
|
+
|
|
27
|
+
### Per-method delta
|
|
28
|
+
|
|
29
|
+
Partner operations live on `sodax.partners.feeClaim` (a `PartnerFeeClaimService`), not directly on `sodax.partners`. v1 method names also changed:
|
|
30
|
+
|
|
31
|
+
```diff
|
|
32
|
+
- await sodax.partners.claimFees({ /* … */ }, spokeProvider);
|
|
33
|
+
+ // Approve once, then configure auto-swap preference, then run swaps.
|
|
34
|
+
+ // Full method list lives in integration/features/auxiliary-services.md.
|
|
35
|
+
+ const approved = await sodax.partners.feeClaim.isTokenApproved({ token, srcAddress });
|
|
36
|
+
+ if (approved.ok && !approved.value) {
|
|
37
|
+
+ await sodax.partners.feeClaim.approveToken({
|
|
38
|
+
+ params: { token, amount },
|
|
39
|
+
+ raw: false,
|
|
40
|
+
+ walletProvider,
|
|
41
|
+
+ });
|
|
42
|
+
+ }
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Pitfalls
|
|
46
|
+
|
|
47
|
+
1. **Partner methods moved.** They live on `sodax.partners.feeClaim`, not `sodax.partners` directly. The parent only exposes `feeClaim` and `config` as public fields.
|
|
48
|
+
2. **All 5 v1 partner errors collapse to `feature: 'partner'`.** Even though they share the `EXECUTION_FAILED` code with every other feature.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## `RecoveryService`
|
|
53
|
+
|
|
54
|
+
**No v1 equivalent.** v1 didn't have a public recovery service. Failed cross-chain operations had to be handled ad-hoc.
|
|
55
|
+
|
|
56
|
+
If you have v1 code that worked around this (e.g. manually walked the hub wallet abstraction to find stuck assets), replace it with `fetchHubAssetBalances` + `withdrawHubAsset`:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const balances = await sodax.recovery.fetchHubAssetBalances({ /* user / hub-wallet args */ });
|
|
60
|
+
if (balances.ok && balances.value.length > 0) {
|
|
61
|
+
await sodax.recovery.withdrawHubAsset({
|
|
62
|
+
params: { /* hub-asset address, amount, destination spoke chain + address */ },
|
|
63
|
+
raw: false,
|
|
64
|
+
walletProvider: sonicWp,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
See [`../../integration/features/auxiliary-services.md`](../../integration/features/auxiliary-services.md) § "RecoveryService".
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## `BackendApiService`
|
|
74
|
+
|
|
75
|
+
The load-bearing v1 → v2 change here is **`Result`-wrapping every method**.
|
|
76
|
+
|
|
77
|
+
### Type / symbol cheat sheet
|
|
78
|
+
|
|
79
|
+
| Method | v1 return | v2 return |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `submitSwapTx` | `Promise<SubmitSwapTxResponse>` | `Promise<Result<SubmitSwapTxResponse>>` |
|
|
82
|
+
| `getIntentByHash` | `Promise<IntentResponse>` | `Promise<Result<IntentResponse>>` |
|
|
83
|
+
| `getIntentByTxHash` | (n/a in v1) | `Promise<Result<IntentResponse>>` (v2-new) |
|
|
84
|
+
| `getOrderbook` (was `getSolverOrderbook`) | `Promise<OrderbookEntry[]>` | `Promise<Result<OrderbookEntry[]>>` |
|
|
85
|
+
| `getUserIntents` (was `getUserSwapHistory`) | `Promise<IntentResponse[]>` | `Promise<Result<IntentResponse[]>>` |
|
|
86
|
+
| `getChains` | `Promise<ChainConfig[]>` | `Promise<Result<GetChainsApiResponse>>` |
|
|
87
|
+
| `getSwapTokens` | `Promise<SwapTokenConfig>` | `Promise<Result<GetSwapTokensApiResponse>>` |
|
|
88
|
+
| `getSwapTokensByChainId` | `Promise<XToken[]>` | `Promise<Result<XToken[]>>` |
|
|
89
|
+
| `getMoneyMarketTokens` | `Promise<MMTokenConfig>` | `Promise<Result<GetMoneyMarketTokensApiResponse>>` |
|
|
90
|
+
| `getMoneyMarketTokensByChainId` | `Promise<XToken[]>` | `Promise<Result<XToken[]>>` |
|
|
91
|
+
| `SubmitSwapTxRequest.srcChainId` | numeric chain id | renamed → `srcChainKey: SpokeChainKey` |
|
|
92
|
+
| `SubmitSwapTxRequest.relayData` | `RelayExtraData` object | now `string` (use `relayData.payload`) |
|
|
93
|
+
|
|
94
|
+
### Per-method delta
|
|
95
|
+
|
|
96
|
+
```diff
|
|
97
|
+
- const response: SubmitSwapTxResponse = await sodax.backendApi.submitSwapTx(request);
|
|
98
|
+
- // throws on failure
|
|
99
|
+
+ const result = await sodax.backendApi.submitSwapTx({
|
|
100
|
+
+ txHash: spokeTxHash as string,
|
|
101
|
+
+ srcChainKey: src.chain, // was: srcChainId
|
|
102
|
+
+ walletAddress: '0x…',
|
|
103
|
+
+ intent: swapIntentData,
|
|
104
|
+
+ relayData: relayData.payload, // was: relayData (object)
|
|
105
|
+
+ });
|
|
106
|
+
+ if (!result.ok) {
|
|
107
|
+
+ // result.error: SodaxError with feature: 'swap', context.api: 'backend'
|
|
108
|
+
+ return;
|
|
109
|
+
+ }
|
|
110
|
+
+ const response = result.value;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Custom `IConfigApi` (sandbox / test fixtures)
|
|
114
|
+
|
|
115
|
+
If you implemented `IConfigApi` for a sandbox or test fixture:
|
|
116
|
+
|
|
117
|
+
```diff
|
|
118
|
+
const sandboxApi: IConfigApi = {
|
|
119
|
+
- async getChains(): Promise<ChainConfig[]> {
|
|
120
|
+
- return [/* fixture */];
|
|
121
|
+
- },
|
|
122
|
+
- async getSwapTokens(): Promise<SwapTokenConfig> { /* … */ },
|
|
123
|
+
+ async getChains(): Promise<Result<ChainConfig[], unknown>> {
|
|
124
|
+
+ return { ok: true, value: [/* fixture */] };
|
|
125
|
+
+ },
|
|
126
|
+
+ async getSwapTokens(): Promise<Result<SwapTokenConfig, unknown>> { /* … */ },
|
|
127
|
+
// …5 methods total
|
|
128
|
+
};
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Every method on the contract returns `Promise<Result<T>>` in v2.
|
|
132
|
+
|
|
133
|
+
### Pitfalls
|
|
134
|
+
|
|
135
|
+
1. **`SubmitSwapTxRequest.relayData` is `string`, not the `RelayExtraData` object.** v1 took the object; v2 takes the `payload` field as a string.
|
|
136
|
+
2. **Backend errors carry `error.context.api === 'backend'`** but the `feature` reflects the call site (`'swap'` for `submitSwapTx`, `'moneyMarket'` for MM-related backend calls, etc.). Use both for logger tag pairs.
|
|
137
|
+
3. **Custom `IConfigApi` implementations must return `Result<T>`** — old throw-on-error implementations will compile-error against the v2 interface.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Verification
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
pnpm -C <your-app-dir> checkTs
|
|
145
|
+
|
|
146
|
+
# Targeted scans:
|
|
147
|
+
grep -rE "spokeProvider:\s*\w+|isPartnerError\b|PartnerFeeClaimError\b" src/
|
|
148
|
+
grep -rE "srcChainId:\s*\w+|\.relayData(?!\s*\.payload)" src/ # legacy field name + non-string relayData
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Cross-references
|
|
152
|
+
|
|
153
|
+
- v2 auxiliary services usage: [`../../integration/features/auxiliary-services.md`](../../integration/features/auxiliary-services.md).
|
|
154
|
+
- `submitSwapTx` flow with `createIntent` upstream: [`./swap.md`](swap.md) (the swap migration covers the request-shape changes in detail).
|
|
155
|
+
- Result/error model: [`../breaking-changes/result-and-errors.md`](../breaking-changes/result-and-errors.md).
|
|
156
|
+
- `IConfigApi` Result-wrapping cross-cutting note: [`../breaking-changes/type-system.md`](../breaking-changes/type-system.md) § 6.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Bridge migration — v1 → v2
|
|
2
|
+
|
|
3
|
+
Pure-SDK migration playbook for `BridgeService`.
|
|
4
|
+
|
|
5
|
+
Pair: [`../../integration/features/bridge.md`](../../integration/features/bridge.md).
|
|
6
|
+
|
|
7
|
+
## TL;DR
|
|
8
|
+
|
|
9
|
+
1. **Drop `spokeProvider`. Pass `walletProvider` directly.**
|
|
10
|
+
2. **Add `srcChainKey` + `srcAddress` to `CreateBridgeParams<K>`.** Generic added.
|
|
11
|
+
3. **`bridge()` returns `Result<TxHashPair>`.** v1 returned a single `string` tx hash; v2 returns `{ srcChainTxHash, dstChainTxHash }` (the spoke + hub tx hashes) wrapped in `Result`.
|
|
12
|
+
4. **`createBridgeIntent()` is spoke-only — no relay.** Same shape as the swap `createIntent`: returns `{ tx, intent, relayData }` for the spoke transaction. Useful when you need manual relay control.
|
|
13
|
+
5. **Read methods reshaped.** `getBridgeableAmount` returns `Promise<Result<BridgeLimit>>` (was `Promise<bigint>`) and now takes two `XToken` objects. `getBridgeableTokens` is synchronous (was async) and takes `(from, to, token)`.
|
|
14
|
+
6. **Errors → `SodaxError` + `Result<T>`.** v1's `BridgeError<BridgeErrorCode>` is gone.
|
|
15
|
+
|
|
16
|
+
## Type / symbol cheat sheet
|
|
17
|
+
|
|
18
|
+
### Field-level renames
|
|
19
|
+
|
|
20
|
+
| Type | v1 shape | v2 shape | Notes |
|
|
21
|
+
|---|---|---|---|
|
|
22
|
+
| `CreateBridgeParams` | `{ srcAsset, amount, dstChainId, dstAddress, dstAsset }` | `{ srcChainKey, srcAddress, srcAsset, amount, dstChainKey, dstAddress, dstAsset }` | Now generic `<K>`. `srcChainId`/`dstChainId` (where they appeared) → `srcChainKey`/`dstChainKey`. |
|
|
23
|
+
| Bridge action wrapper | `{ params, spokeProvider }` | `{ params, raw: false, walletProvider }` | Same as every feature. |
|
|
24
|
+
| `bridge` return | `Promise<string>` (tx hash, throws on error) | `Promise<Result<TxHashPair, SodaxError>>` | Tx-pair + Result. |
|
|
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)`). |
|
|
26
|
+
| `getBridgeableTokens` | `Promise<XToken[]>` | `Result<XToken[], SodaxError>` (synchronous) | Sync now (config-derived). Takes `(from: SpokeChainKey, to: SpokeChainKey, token: string)` — was `(srcToken: XToken)`. |
|
|
27
|
+
|
|
28
|
+
### Deleted symbols
|
|
29
|
+
|
|
30
|
+
- `BridgeError<BridgeErrorCode>` and `isBridgeError` — replaced by `SodaxError<C>` + `feature: 'bridge'`.
|
|
31
|
+
|
|
32
|
+
### v1 → v2 error code crosswalk (bridge-specific)
|
|
33
|
+
|
|
34
|
+
| v1 `BridgeErrorCode` | v2 code + context |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `BRIDGE_FAILED` | `EXECUTION_FAILED` (`action: 'bridge'`) |
|
|
37
|
+
| `CREATE_BRIDGE_INTENT_FAILED` | `INTENT_CREATION_FAILED` (`action: 'bridge'`) |
|
|
38
|
+
| `GET_BRIDGEABLE_AMOUNT_FAILED` | `LOOKUP_FAILED` (`method: 'getBridgeableAmount'`) |
|
|
39
|
+
| `GET_BRIDGEABLE_TOKENS_FAILED` | `LOOKUP_FAILED` (`method: 'getBridgeableTokens'`) |
|
|
40
|
+
|
|
41
|
+
## Per-method delta
|
|
42
|
+
|
|
43
|
+
### `bridge`
|
|
44
|
+
|
|
45
|
+
```diff
|
|
46
|
+
- const txHash: string = await sodax.bridge.bridge({
|
|
47
|
+
- params: { srcAsset, amount, dstChainId, dstAddress, dstAsset },
|
|
48
|
+
- spokeProvider,
|
|
49
|
+
- });
|
|
50
|
+
+ const result = await sodax.bridge.bridge({
|
|
51
|
+
+ params: {
|
|
52
|
+
+ srcChainKey: ChainKeys.ARBITRUM_MAINNET,
|
|
53
|
+
+ srcAddress: '0x…',
|
|
54
|
+
+ srcAsset, amount,
|
|
55
|
+
+ dstChainKey: ChainKeys.STELLAR_MAINNET,
|
|
56
|
+
+ dstAddress: 'G…',
|
|
57
|
+
+ dstAsset,
|
|
58
|
+
+ },
|
|
59
|
+
+ raw: false,
|
|
60
|
+
+ walletProvider,
|
|
61
|
+
+ });
|
|
62
|
+
+ if (!result.ok) return;
|
|
63
|
+
+ const { srcChainTxHash, dstChainTxHash } = result.value;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `createBridgeIntent`
|
|
67
|
+
|
|
68
|
+
```diff
|
|
69
|
+
- await sodax.bridge.createBridgeIntent({ params, spokeProvider });
|
|
70
|
+
+ const result = await sodax.bridge.createBridgeIntent({ params, raw: false, walletProvider });
|
|
71
|
+
+ if (!result.ok) return;
|
|
72
|
+
+ const { tx, intent, relayData } = result.value;
|
|
73
|
+
+ // Submit relayData.payload via your custom relay if needed.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### `getBridgeableAmount` / `getBridgeableTokens`
|
|
77
|
+
|
|
78
|
+
```diff
|
|
79
|
+
- const amount: bigint = await sodax.bridge.getBridgeableAmount(srcChainId, srcToken.address, dstChainId, dstToken.address);
|
|
80
|
+
+ const result = await sodax.bridge.getBridgeableAmount(srcToken, dstToken); // both are XToken objects (each carries chainKey)
|
|
81
|
+
+ // result.value is BridgeLimit = { amount, decimals, type }, not a raw bigint.
|
|
82
|
+
+ if (!result.ok) return 0n;
|
|
83
|
+
+ const amount = result.value;
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `approve` / `isAllowanceValid`
|
|
87
|
+
|
|
88
|
+
Standard pattern:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
await sodax.bridge.approve({
|
|
92
|
+
params: { srcChainKey, srcAddress, srcAsset, amount },
|
|
93
|
+
raw: false,
|
|
94
|
+
walletProvider,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const allowed = await sodax.bridge.isAllowanceValid({
|
|
98
|
+
params: { srcChainKey, srcAddress, srcAsset, amount },
|
|
99
|
+
raw: true, // read-only
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Pitfalls
|
|
104
|
+
|
|
105
|
+
Cross-cutting traps (Result destructuring, error-model migration, srcChain/dstChain renames, etc.) live in [`../ai-rules.md`](../ai-rules.md). The list below is feature-specific — typecheck fingerprints, return-shape diffs, and gotchas unique to this feature.
|
|
106
|
+
|
|
107
|
+
1. **Treating `bridge` return as a string.** v2 returns `Result<TxHashPair>`. Destructure both elements; cast to string at the boundary if your downstream API expects a string.
|
|
108
|
+
2. **`getBridgeableAmount` reshaped.** Resolves to `Result<BridgeLimit, SodaxError>` (with `BridgeLimit = { amount, decimals, type }`), not raw `Result<bigint>`. UI code that displayed the bigint directly needs `result.value.amount`.
|
|
109
|
+
3. **`getBridgeableTokens` is synchronous now.** It returns `Result<XToken[]>` directly (no `await`). v1 was a `Promise`. `await` still typechecks but `.then(...)` is a runtime error.
|
|
110
|
+
4. **Tokens are bridgeable iff they share the same vault.** Same chain pair, same underlying — but if you bridge USDC.e on chain A and the destination's USDC has a different vault, the call rejects with `VALIDATION_FAILED`. Use `getBridgeableTokens(srcChainKey, dstChainKey, srcAsset.address)` to enumerate compatible destinations.
|
|
111
|
+
4. **`createBridgeIntent` is spoke-only — no relay.** If you call it expecting a finished bridge, you'll have a pending hub-side transfer that never executes. Either use `bridge()` for the full flow, or call the relay layer manually after `createBridgeIntent`.
|
|
112
|
+
|
|
113
|
+
## Verification
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pnpm -C <your-app-dir> checkTs
|
|
117
|
+
|
|
118
|
+
grep -rE "spokeProvider:\s*\w+|isBridgeError\b|BridgeError\b" src/
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Cross-references
|
|
122
|
+
|
|
123
|
+
- v2 bridge usage: [`../../integration/features/bridge.md`](../../integration/features/bridge.md).
|
|
124
|
+
- Stellar destination trustline: [`../../integration/chain-specifics.md`](../../integration/chain-specifics.md).
|
|
125
|
+
- Cross-cutting prerequisites listed in [`../README.md`](../README.md).
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# DEX migration — v1 → v2
|
|
2
|
+
|
|
3
|
+
Pure-SDK migration playbook for `DexService` (`AssetService` + `ClService`).
|
|
4
|
+
|
|
5
|
+
Pair: [`../../integration/features/dex.md`](../../integration/features/dex.md).
|
|
6
|
+
|
|
7
|
+
## TL;DR
|
|
8
|
+
|
|
9
|
+
1. **Drop `spokeProvider`. Pass `walletProvider` directly.** Same as every other feature.
|
|
10
|
+
2. **Add `srcChainKey` + `srcAddress` to every action params.** All 6 DEX param types (`CreateAssetDepositParams`, `CreateAssetWithdrawParams`, `ClSupplyParams`, `ClIncreaseLiquidityParams`, `ClDecreaseLiquidityParams`, `ClClaimRewardsParams`) gained both fields and a `<K extends SpokeChainKey>` generic.
|
|
11
|
+
3. **`getPools()` is synchronous in v2.** Was `Promise<PoolKey[]>`; now plain `PoolKey[]`. `.then(...)` is a runtime error.
|
|
12
|
+
4. **`getAssetsForPool` is chain-key-first.** Was `getAssetsForPool(spokeProvider, poolKey)`; now `getAssetsForPool(srcChainKey, poolKey)`.
|
|
13
|
+
5. **`getDeposit` is `Result`-wrapped.** Was `(token, spokeProvider) => Promise<bigint>`; now `(poolToken, walletAddress, chainKey) => Promise<Result<bigint>>`.
|
|
14
|
+
6. **Read-only allowance checks pass `raw: true`.** `assetService.isAllowanceValid` requires the `WalletProviderSlot<K, Raw>` discriminator; the read doesn't actually consult the wallet provider, so `raw: true` is the contract for read-only access.
|
|
15
|
+
7. **`getPoolData` and `getPositionInfo` use the hub publicClient.** Consumers can pass `sodax.hubProvider.publicClient` when needed.
|
|
16
|
+
8. **Errors → `SodaxError` + `Result<T>`.** v1's `ConcentratedLiquidityError`, `AssetServiceError` and their type guards are gone.
|
|
17
|
+
|
|
18
|
+
## Type / symbol cheat sheet
|
|
19
|
+
|
|
20
|
+
### Field-level renames
|
|
21
|
+
|
|
22
|
+
| Type | v1 shape | v2 shape | Notes |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| `CreateAssetDepositParams` | `{ asset, amount, poolToken, dst? }` | `{ srcChainKey, srcAddress, asset, amount, poolToken, dst? }` | Now generic `<K>`. |
|
|
25
|
+
| `CreateAssetWithdrawParams` | same | same with `srcChainKey, srcAddress` | |
|
|
26
|
+
| `ClSupplyParams` | `{ poolKey, tickLower, tickUpper, liquidity, amount0Max, amount1Max, sqrtPriceX96 }` | + `srcChainKey, srcAddress` | |
|
|
27
|
+
| `ClIncreaseLiquidityParams` | `+ tokenId` | + `srcChainKey, srcAddress` | |
|
|
28
|
+
| `ClDecreaseLiquidityParams` | `{ poolKey, tokenId, liquidity, amount0Min, amount1Min }` | + `srcChainKey, srcAddress` | |
|
|
29
|
+
| `ClClaimRewardsParams` | `{ poolKey, tokenId, tickLower, tickUpper }` | + `srcChainKey, srcAddress` | |
|
|
30
|
+
| `getAssetsForPool` | `(spokeProvider, poolKey)` | `(srcChainKey, poolKey)` | Chain-key-first. Sync. |
|
|
31
|
+
| `getPools` | `Promise<PoolKey[]>` | `PoolKey[]` | Sync now. |
|
|
32
|
+
| `getDeposit` | `(token, spokeProvider) => Promise<bigint>` | `(poolToken, walletAddress, chainKey) => Promise<Result<bigint>>` | Result-wrapped. |
|
|
33
|
+
|
|
34
|
+
### Deleted symbols
|
|
35
|
+
|
|
36
|
+
- `ConcentratedLiquidityError<ConcentratedLiquidityErrorCode>` and `AssetServiceError<AssetServiceErrorCode>` plus their type guards — replaced by `SodaxError<C>` + `feature: 'dex'`.
|
|
37
|
+
- v1 `getDeposit(token, spokeProvider)` overload — replaced by the chain-key-first signature.
|
|
38
|
+
|
|
39
|
+
### v1 → v2 error code crosswalk (DEX-specific)
|
|
40
|
+
|
|
41
|
+
| v1 code | v2 code + context |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `DEPOSIT_FAILED` | `EXECUTION_FAILED` (`action: 'deposit'`) |
|
|
44
|
+
| `WITHDRAW_FAILED` | `EXECUTION_FAILED` (`action: 'withdraw'`) |
|
|
45
|
+
| `SUPPLY_LIQUIDITY_FAILED` | `EXECUTION_FAILED` (`action: 'supplyLiquidity'`) |
|
|
46
|
+
| `INCREASE_LIQUIDITY_FAILED` | `EXECUTION_FAILED` (`action: 'increaseLiquidity'`) |
|
|
47
|
+
| `DECREASE_LIQUIDITY_FAILED` | `EXECUTION_FAILED` (`action: 'decreaseLiquidity'`) |
|
|
48
|
+
| `CLAIM_REWARDS_FAILED` | `EXECUTION_FAILED` (`action: 'claimRewards'`) |
|
|
49
|
+
| `GET_POOL_DATA_FAILED` | `LOOKUP_FAILED` (`method: 'getPoolData'`) |
|
|
50
|
+
| `GET_POSITION_INFO_FAILED` | `LOOKUP_FAILED` (`method: 'getPositionInfo'`) |
|
|
51
|
+
|
|
52
|
+
## Per-method delta
|
|
53
|
+
|
|
54
|
+
### `deposit` / `withdraw`
|
|
55
|
+
|
|
56
|
+
```diff
|
|
57
|
+
- await sodax.dex.assetService.deposit({ params, spokeProvider });
|
|
58
|
+
+ const result = await sodax.dex.assetService.deposit({
|
|
59
|
+
+ params: { srcChainKey, srcAddress, asset, amount, poolToken },
|
|
60
|
+
+ raw: false,
|
|
61
|
+
+ walletProvider,
|
|
62
|
+
+ });
|
|
63
|
+
+ if (!result.ok) return;
|
|
64
|
+
+ const { srcChainTxHash, dstChainTxHash } = result.value;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### `supplyLiquidity` (mint new) and `increaseLiquidity` (existing)
|
|
68
|
+
|
|
69
|
+
The pure-helper `createSupplyLiquidityParamsProps` returns the helper-relevant subset (no `srcChainKey`/`srcAddress`). Spread it at the call site:
|
|
70
|
+
|
|
71
|
+
```diff
|
|
72
|
+
- const params = createSupplyLiquidityParamsProps({ /* … */ });
|
|
73
|
+
- await sodax.dex.clService.supplyLiquidity({ params, spokeProvider });
|
|
74
|
+
+ const helperOutput = createSupplyLiquidityParamsProps({ /* … */ });
|
|
75
|
+
+ const srcAddress = (await walletProvider.getWalletAddress()) as `0x${string}`;
|
|
76
|
+
+ const params = { ...helperOutput, srcChainKey, srcAddress };
|
|
77
|
+
+ const result = await sodax.dex.clService.supplyLiquidity({ params, raw: false, walletProvider });
|
|
78
|
+
+ if (!result.ok) return;
|
|
79
|
+
+ const { dstChainTxHash } = result.value;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `getAssetsForPool`
|
|
83
|
+
|
|
84
|
+
```diff
|
|
85
|
+
- const { token0, token1 } = sodax.dex.clService.getAssetsForPool(spokeProvider, poolKey);
|
|
86
|
+
+ const { token0, token1 } = sodax.dex.clService.getAssetsForPool(srcChainKey, poolKey);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `getPools`
|
|
90
|
+
|
|
91
|
+
```diff
|
|
92
|
+
- const pools = await sodax.dex.clService.getPools();
|
|
93
|
+
+ const pools = sodax.dex.clService.getPools(); // sync
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The `await` form still compiles (TS allows `await` on non-promises) but `.then(...)` is a runtime error.
|
|
97
|
+
|
|
98
|
+
### `getDeposit`
|
|
99
|
+
|
|
100
|
+
```diff
|
|
101
|
+
- const balance: bigint = await sodax.dex.assetService.getDeposit(poolToken, spokeProvider);
|
|
102
|
+
+ const result = await sodax.dex.assetService.getDeposit(poolToken, walletAddress, chainKey);
|
|
103
|
+
+ if (!result.ok) return 0n;
|
|
104
|
+
+ const balance = result.value;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Allowance (read-only `raw: true`)
|
|
108
|
+
|
|
109
|
+
```diff
|
|
110
|
+
- const allowed = await sodax.dex.assetService.isAllowanceValid({ params, spokeProvider });
|
|
111
|
+
+ const result = await sodax.dex.assetService.isAllowanceValid({ params, raw: true });
|
|
112
|
+
+ if (!result.ok) return false;
|
|
113
|
+
+ const allowed = result.value;
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Pitfalls
|
|
117
|
+
|
|
118
|
+
Cross-cutting traps (Result destructuring, error-model migration, srcChain/dstChain renames, etc.) live in [`../ai-rules.md`](../ai-rules.md). The list below is feature-specific — typecheck fingerprints, return-shape diffs, and gotchas unique to this feature.
|
|
119
|
+
|
|
120
|
+
1. **Forgetting `raw: true` on `isAllowanceValid`.** TypeScript error: `Property 'walletProvider' is missing`.
|
|
121
|
+
2. **Passing `spokeProvider` to `getAssetsForPool`.** Type error — pass `srcChainKey` instead.
|
|
122
|
+
3. **`getPools().then(...)` runtime error** — sync now.
|
|
123
|
+
4. **Reading `spokeProvider.chainConfig.chain.name` for display.** Gone. Use `baseChainInfo[chainKey]?.name` from `@sodax/sdk`.
|
|
124
|
+
5. **Reading `spokeProvider.walletProvider.getWalletAddress()`.** Gone. The wallet provider you passed is the same one you read from — call its `.getWalletAddress()` directly.
|
|
125
|
+
6. **`walletProvider.getWalletAddress()` returns `Promise<string>`, not the EVM-branded `` `0x${string}` ``.** SDK params want `GetAddressType<K>`, which for EVM resolves to `` `0x${string}` ``. Cast at the boundary: `(await walletProvider.getWalletAddress()) as \`0x${string}\``.
|
|
126
|
+
7. **Mint-new vs increase-existing are two distinct SDK methods.** v2 has `clService.supplyLiquidity` (mint) and `clService.increaseLiquidity` (existing tokenId). Pick the right one at the call site based on whether you have an existing position id.
|
|
127
|
+
8. **`assetService.deposit` and `withdraw` always relay to hub.** If you need spoke-only execution (custom orchestration), use `assetService.executeDeposit` directly — but it's not surfaced through the higher-level wrappers.
|
|
128
|
+
|
|
129
|
+
## Verification
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pnpm -C <your-app-dir> checkTs
|
|
133
|
+
|
|
134
|
+
# Targeted scans:
|
|
135
|
+
grep -rE "spokeProvider:\s*\w+|getAssetsForPool\([^,]*Provider" src/
|
|
136
|
+
grep -rE "isConcentratedLiquidityError\b|ConcentratedLiquidityError\b|AssetServiceError\b" src/
|
|
137
|
+
grep -rE "getPools\(\)\.then\b" src/
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Cross-references
|
|
141
|
+
|
|
142
|
+
- v2 DEX usage: [`../../integration/features/dex.md`](../../integration/features/dex.md).
|
|
143
|
+
- Cross-cutting prerequisites listed in [`../README.md`](../README.md).
|