@sodax/sdk 1.5.7-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 +32076 -31544
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8604 -7136
- package/dist/index.d.ts +8604 -7136
- package/dist/index.mjs +31893 -31402
- package/dist/index.mjs.map +1 -1
- package/package.json +19 -11
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Swap migration — v1 → v2
|
|
2
|
+
|
|
3
|
+
Pure-SDK migration playbook for `SwapService`.
|
|
4
|
+
|
|
5
|
+
Pair: [`../../integration/features/swap.md`](../../integration/features/swap.md).
|
|
6
|
+
|
|
7
|
+
## TL;DR
|
|
8
|
+
|
|
9
|
+
1. **Drop the `*SpokeProvider` argument.** Pass `walletProvider` directly into the SDK call payload alongside `params` and `raw: false`.
|
|
10
|
+
2. **Add `raw: false` (or `raw: true`) to every call shape.** Without it, TypeScript can't pick a branch of `WalletProviderSlot` and rejects `walletProvider`.
|
|
11
|
+
3. **Field renames on `CreateIntentParams<K>` and `CreateLimitOrderParams<K>`:**
|
|
12
|
+
- `srcChain` → `srcChainKey`
|
|
13
|
+
- `dstChain` → `dstChainKey`
|
|
14
|
+
- **`Intent.srcChain` / `Intent.dstChain` are unchanged** (read shape) — they're `IntentRelayChainId` (bigint).
|
|
15
|
+
4. **`CreateIntentResult` shape changed.** v1 was a tuple `[spokeTxHash, intent, relayData]`; v2 is an object `{ tx, intent, relayData }`. Destructure accordingly.
|
|
16
|
+
5. **`SubmitSwapTxRequest.srcChainId` → `srcChainKey`.** And `relayData` field on the request expects a **string** (`relayData.payload`), not the `RelayExtraData` object.
|
|
17
|
+
6. **Errors → `SodaxError` + `Result<T>`.** v1's `IntentError<IntentErrorCode>` is gone. Branch on `result.ok`; use `(error.feature, error.code)` for discrimination.
|
|
18
|
+
|
|
19
|
+
## Type / symbol cheat sheet
|
|
20
|
+
|
|
21
|
+
### Field-level renames
|
|
22
|
+
|
|
23
|
+
| Type | v1 field | v2 field | Notes |
|
|
24
|
+
|---|---|---|---|
|
|
25
|
+
| `CreateIntentParams` (request) | `srcChain`, `dstChain` | `srcChainKey`, `dstChainKey` | Now generic: `CreateIntentParams<K extends SpokeChainKey>`. |
|
|
26
|
+
| `CreateLimitOrderParams` (request) | `srcChain`, `dstChain` | `srcChainKey`, `dstChainKey` | `Omit<CreateIntentParams<K>, 'deadline'>`. |
|
|
27
|
+
| `SubmitSwapTxRequest` (backend req) | `srcChainId` | `srcChainKey` | And `relayData: string` (was the object in v1). |
|
|
28
|
+
| `Intent` (read shape) | `srcChain`, `dstChain` | **unchanged** | `IntentRelayChainId` (bigint). Don't grep-replace blindly. |
|
|
29
|
+
| `XToken` | `xChainId` | `chainKey` | Type renamed from `Token` → `XToken`. |
|
|
30
|
+
| `CreateIntentResult` | tuple `[spokeTxHash, intent, relayData]` | object `{ tx, intent, relayData }` | Generic: `CreateIntentResult<K, Raw>`. |
|
|
31
|
+
|
|
32
|
+
### Deleted symbols
|
|
33
|
+
|
|
34
|
+
- The `SpokeProvider` union and per-chain `*SpokeProvider` classes — gone. v2 takes `walletProvider` directly. See [`../breaking-changes/architecture.md`](../breaking-changes/architecture.md) § 1.
|
|
35
|
+
- `IntentError<IntentErrorCode>` and `isIntentError` / `isIntentPostExecutionFailedError` / `isIntentSubmitTxFailedError` type guards. Replaced by `isSodaxError` + feature/code discrimination.
|
|
36
|
+
- `CustomProvider` (Hana wallet window typedecl) — declare `unknown` or import directly from the wallet vendor.
|
|
37
|
+
- `hubAssets` global — gone. `XToken.vault` and `XToken.hubAsset` baked in.
|
|
38
|
+
|
|
39
|
+
### v1 → v2 error code crosswalk (swap-specific)
|
|
40
|
+
|
|
41
|
+
| v1 `IntentErrorCode` | v2 `SodaxErrorCode` + context |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `CREATE_INTENT_FAILED` | `INTENT_CREATION_FAILED` (`action: 'createIntent'`) |
|
|
44
|
+
| `CREATE_LIMIT_ORDER_FAILED` | `INTENT_CREATION_FAILED` (`action: 'createLimitOrder'`) |
|
|
45
|
+
| `POST_EXECUTION_FAILED` | `EXECUTION_FAILED` (`action: 'swap'`, `phase: 'postExecution'`) |
|
|
46
|
+
| `SOLVER_API_ERROR` | `EXTERNAL_API_ERROR` (`api: 'solver'`, with `solverCode`/`solverDetail` on context) |
|
|
47
|
+
| `SIMULATION_FAILED` | `EXECUTION_FAILED` (`phase: 'execution'`) |
|
|
48
|
+
| `SUBMIT_TX_FAILED` (relay) | `TX_SUBMIT_FAILED` (`relayCode: 'SUBMIT_TX_FAILED'`) |
|
|
49
|
+
| `RELAY_TIMEOUT` | `RELAY_TIMEOUT` (unchanged code; still on `relayCode`) |
|
|
50
|
+
|
|
51
|
+
## Per-method delta
|
|
52
|
+
|
|
53
|
+
### `swap`
|
|
54
|
+
|
|
55
|
+
```diff
|
|
56
|
+
- await sodax.swaps.swap({
|
|
57
|
+
- intentParams,
|
|
58
|
+
- spokeProvider: sourceSpokeProvider,
|
|
59
|
+
- });
|
|
60
|
+
+ const result = await sodax.swaps.swap({
|
|
61
|
+
+ params: intentParams,
|
|
62
|
+
+ raw: false,
|
|
63
|
+
+ walletProvider: sourceWalletProvider,
|
|
64
|
+
+ });
|
|
65
|
+
+ if (!result.ok) return;
|
|
66
|
+
+ const { spokeTxHash, intent, relayData } = result.value;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### `createIntent`
|
|
70
|
+
|
|
71
|
+
```diff
|
|
72
|
+
- const [spokeTxHash, intent, relayData] = await sodax.swaps.createIntent({
|
|
73
|
+
- intentParams,
|
|
74
|
+
- spokeProvider: sourceSpokeProvider,
|
|
75
|
+
- });
|
|
76
|
+
+ const result = await sodax.swaps.createIntent({
|
|
77
|
+
+ params: intentParams,
|
|
78
|
+
+ raw: false,
|
|
79
|
+
+ walletProvider: sourceWalletProvider,
|
|
80
|
+
+ });
|
|
81
|
+
+ if (!result.ok) return;
|
|
82
|
+
+ const { tx: spokeTxHash, intent, relayData } = result.value;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `createLimitOrder`
|
|
86
|
+
|
|
87
|
+
Same as `createIntent` shape (with `CreateLimitOrderParams`). v1 took `{ limitOrderParams, spokeProvider }`; v2 takes `{ params, raw: false, walletProvider }`.
|
|
88
|
+
|
|
89
|
+
### `cancelIntent` / `cancelLimitOrder`
|
|
90
|
+
|
|
91
|
+
```diff
|
|
92
|
+
- await sodax.swaps.cancelIntent({ srcChain, intent, spokeProvider });
|
|
93
|
+
+ await sodax.swaps.cancelIntent({
|
|
94
|
+
+ params: { srcChainKey, intent },
|
|
95
|
+
+ raw: false,
|
|
96
|
+
+ walletProvider,
|
|
97
|
+
+ });
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `approve` / `isAllowanceValid`
|
|
101
|
+
|
|
102
|
+
v1: `await sodax.swaps.approve({ intentParams, spokeProvider })`.
|
|
103
|
+
v2: `await sodax.swaps.approve({ params: intentParams, raw: false, walletProvider })`.
|
|
104
|
+
|
|
105
|
+
For `isAllowanceValid` in **read-only** flows (e.g. UI polling), use `raw: true` to skip the wallet-provider requirement:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
const result = await sodax.swaps.isAllowanceValid({ params, raw: true });
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The underlying read doesn't consult the wallet provider; `raw: true` is the contract for read-only access.
|
|
112
|
+
|
|
113
|
+
### Backend submit-tx (`SubmitSwapTxRequest`)
|
|
114
|
+
|
|
115
|
+
```diff
|
|
116
|
+
const request: SubmitSwapTxRequest = {
|
|
117
|
+
txHash: spokeTxHash as string,
|
|
118
|
+
- srcChainId: sourceChain,
|
|
119
|
+
+ srcChainKey: src.chain,
|
|
120
|
+
walletAddress: sourceAccount.address ?? '',
|
|
121
|
+
intent: swapIntentData,
|
|
122
|
+
- relayData, // was the RelayExtraData object
|
|
123
|
+
+ relayData: relayData.payload, // now a string
|
|
124
|
+
};
|
|
125
|
+
const submitResult = await sodax.backendApi.submitSwapTx(request);
|
|
126
|
+
if (!submitResult.ok) return;
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Worked example — `handleSubmitTxSwap` flow
|
|
130
|
+
|
|
131
|
+
```diff
|
|
132
|
+
const handleSubmitTxSwap = async (intentOrderPayload: CreateIntentParams) => {
|
|
133
|
+
- if (!sourceProvider) return;
|
|
134
|
+
+ if (!sourceWalletProvider) return;
|
|
135
|
+
- const createIntentResult = await sodax.swaps.createIntent({
|
|
136
|
+
- intentParams: intentOrderPayload,
|
|
137
|
+
- spokeProvider: sourceProvider,
|
|
138
|
+
- });
|
|
139
|
+
+ const createIntentResult = await sodax.swaps.createIntent({
|
|
140
|
+
+ params: intentOrderPayload,
|
|
141
|
+
+ raw: false,
|
|
142
|
+
+ walletProvider: sourceWalletProvider,
|
|
143
|
+
+ });
|
|
144
|
+
if (!createIntentResult.ok) return;
|
|
145
|
+
- const [spokeTxHash, intent, relayData] = createIntentResult.value;
|
|
146
|
+
+ const { tx: spokeTxHash, intent, relayData } = createIntentResult.value;
|
|
147
|
+
const swapIntentData: SwapIntentData = {
|
|
148
|
+
/* … */
|
|
149
|
+
- srcChain: Number(intent.srcChain), // Intent.srcChain still on read shape
|
|
150
|
+
- dstChain: Number(intent.dstChain), // Intent.dstChain still on read shape
|
|
151
|
+
+ srcChain: Number(intent.srcChain), // unchanged — Intent shape kept these
|
|
152
|
+
+ dstChain: Number(intent.dstChain),
|
|
153
|
+
};
|
|
154
|
+
const request: SubmitSwapTxRequest = {
|
|
155
|
+
txHash: spokeTxHash as string,
|
|
156
|
+
- srcChainId: sourceChain,
|
|
157
|
+
+ srcChainKey: src.chain,
|
|
158
|
+
walletAddress: sourceAccount.address ?? '',
|
|
159
|
+
intent: swapIntentData,
|
|
160
|
+
- relayData,
|
|
161
|
+
+ relayData: relayData.payload,
|
|
162
|
+
};
|
|
163
|
+
- await submitSwapTx(request);
|
|
164
|
+
+ const submitResult = await sodax.backendApi.submitSwapTx(request);
|
|
165
|
+
+ if (!submitResult.ok) return;
|
|
166
|
+
};
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Pitfalls
|
|
170
|
+
|
|
171
|
+
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.
|
|
172
|
+
|
|
173
|
+
1. **Over-broad regex on `srcChain` / `dstChain`.** Request types renamed; `Intent` (read shape) didn't. Distinguish "I'm building a request" from "I'm reading an intent."
|
|
174
|
+
2. **`createIntent` success shape changed from tuple to object.** `{ tx, intent, relayData }`, not `[spokeTxHash, intent, relayData]`.
|
|
175
|
+
3. **`relayData` on `SubmitSwapTxRequest` is a `string`.** It's `relayData.payload`, not the full `RelayExtraData` object.
|
|
176
|
+
4. **`spokeTxHash` is `TxReturnType<K, false>`, not necessarily `string`.** For most chains it's a string already, but the SDK type is broader. Cast at the boundary when passing to APIs that strictly want `string`: `txHash: spokeTxHash as string`.
|
|
177
|
+
5. **`Intent.deadline` is `bigint`.** `Math.floor(Date.now() / 1000) + 60 * 5` returns a number; wrap in `BigInt(...)`.
|
|
178
|
+
6. **`IntentResponse.srcChain` / `dstChain` from the backend are `IntentRelayChainId` (number/bigint), not chain keys.** Convert via `sodax.config.getSpokeChainKeyFromIntentRelayChainId(BigInt(intent.dstChain))` when displaying.
|
|
179
|
+
7. **`hubAssets` is gone.** Anything that walked `hubAssets[chainId]` for vault lookup must use `XToken.vault` (now baked in) or `sodax.config.getOriginalAssetAddress()`.
|
|
180
|
+
8. **`SodaxConfig.swaps` vs `.solver`.** v1 mixed solver endpoints under `swaps`; v2 splits — `swaps` for supported tokens, `solver` for endpoints. See [`../breaking-changes/architecture.md`](../breaking-changes/architecture.md) Appendix B.
|
|
181
|
+
|
|
182
|
+
## Verification
|
|
183
|
+
|
|
184
|
+
After migrating swap call sites:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# Should produce zero errors when the migration is complete:
|
|
188
|
+
pnpm -C <your-app-dir> checkTs
|
|
189
|
+
|
|
190
|
+
# Targeted scan for leftover v1 patterns:
|
|
191
|
+
grep -rE "spokeProvider:\s*\w+|intentParams:\s*\w+|srcChain:\s*\w+\.[a-z]+ChainId" src/
|
|
192
|
+
grep -rE "isIntentError\b|isIntentPostExecutionFailedError\b|isIntentSubmitTxFailedError\b" src/
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Cross-references
|
|
196
|
+
|
|
197
|
+
- v2 swap usage: [`../../integration/features/swap.md`](../../integration/features/swap.md).
|
|
198
|
+
- Cross-cutting prerequisites (type-system, architecture, result/errors) listed in [`../README.md`](../README.md).
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Migration recipes — v1 → v2
|
|
2
|
+
|
|
3
|
+
Practical patterns for porting consumer code without rewriting everything in one pass. Three recipes:
|
|
4
|
+
|
|
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. [Error-shape adapter](#2-error-shape-adapter) — adapt v2 `SodaxError` onto v1 `{ code, data }` branches so existing error-formatting helpers keep working.
|
|
7
|
+
3. [Result adapter](#3-result-adapter) — wrap v2 `Result<T>` in a v1-style throw shim for incremental conversion of call sites.
|
|
8
|
+
|
|
9
|
+
These are migration-only — once the port is complete, delete them. They're not patterns for new code.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Codemod patterns
|
|
14
|
+
|
|
15
|
+
### What's safe to grep-replace
|
|
16
|
+
|
|
17
|
+
| Change | Find | Replace | Notes |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| Chain-id constants | `(\w+)_MAINNET_CHAIN_ID` | `ChainKeys.$1_MAINNET` | Mechanical. After: fix `import` statements. |
|
|
20
|
+
| `xChainId` field on `XToken` | `\.xChainId\b` | `.chainKey` | Token field rename. Audit first — some non-token types may use `xChainId` differently. |
|
|
21
|
+
| `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
|
+
| `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
|
+
| `AddressType` → `BtcAddressType` | `\bAddressType\b` (in `@sodax/types` import positions) | `BtcAddressType` | |
|
|
24
|
+
|
|
25
|
+
### What's not safe to grep-replace
|
|
26
|
+
|
|
27
|
+
- `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.
|
|
28
|
+
- `spokeProvider` → `walletProvider`. The replacement isn't 1-to-1 (`spokeProvider` was a class instance; `walletProvider` is a separate field). You're better off doing this manually per call site.
|
|
29
|
+
- `instanceof EvmSpokeProvider` → chain-key check. Chain-specific replacement varies (some need `chainKey === ChainKeys.X`, some `getChainType(chainKey) === 'EVM'`).
|
|
30
|
+
|
|
31
|
+
### `ts-morph` script for chain-id imports
|
|
32
|
+
|
|
33
|
+
When you have many files, a one-shot script for the chain-id rename. Run from the root of your consumer repo with `tsx codemod-chain-ids.ts`:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
// codemod-chain-ids.ts
|
|
37
|
+
import { Project, SyntaxKind } from 'ts-morph';
|
|
38
|
+
|
|
39
|
+
const project = new Project({ tsConfigFilePath: 'tsconfig.json' });
|
|
40
|
+
const sodaxImports = ['@sodax/types', '@sodax/sdk'];
|
|
41
|
+
const renamed = new Set<string>();
|
|
42
|
+
|
|
43
|
+
for (const file of project.getSourceFiles('src/**/*.{ts,tsx}')) {
|
|
44
|
+
let edited = false;
|
|
45
|
+
|
|
46
|
+
for (const decl of file.getImportDeclarations()) {
|
|
47
|
+
if (!sodaxImports.includes(decl.getModuleSpecifierValue())) continue;
|
|
48
|
+
|
|
49
|
+
const named = decl.getNamedImports();
|
|
50
|
+
const toRemove: typeof named = [];
|
|
51
|
+
let needsChainKeysImport = false;
|
|
52
|
+
|
|
53
|
+
for (const imp of named) {
|
|
54
|
+
const name = imp.getName();
|
|
55
|
+
const m = name.match(/^(.+)_MAINNET_CHAIN_ID$/);
|
|
56
|
+
if (!m) continue;
|
|
57
|
+
const newName = `ChainKeys.${m[1]}_MAINNET`;
|
|
58
|
+
// Replace usages inside the file
|
|
59
|
+
file.forEachDescendant(node => {
|
|
60
|
+
if (node.isKind(SyntaxKind.Identifier) && node.getText() === name) {
|
|
61
|
+
node.replaceWithText(newName);
|
|
62
|
+
edited = true;
|
|
63
|
+
renamed.add(name);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
toRemove.push(imp);
|
|
67
|
+
needsChainKeysImport = true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
for (const imp of toRemove) imp.remove();
|
|
71
|
+
if (needsChainKeysImport) {
|
|
72
|
+
const existing = decl.getNamedImports().find(i => i.getName() === 'ChainKeys');
|
|
73
|
+
if (!existing) decl.addNamedImport('ChainKeys');
|
|
74
|
+
}
|
|
75
|
+
if (decl.getNamedImports().length === 0 && !decl.getNamespaceImport() && !decl.getDefaultImport()) {
|
|
76
|
+
decl.remove();
|
|
77
|
+
edited = true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (edited) await file.save();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log('Renamed constants:', [...renamed].join(', '));
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Exit codes and post-run checks:
|
|
88
|
+
|
|
89
|
+
- **Run `tsc --noEmit` after** — confirm imports resolve. The script doesn't touch `ChainKey` type imports (which you may also need to add manually in some files).
|
|
90
|
+
- **Re-run with `--dry-run`** semantics by commenting out `file.save()` to preview the diff.
|
|
91
|
+
|
|
92
|
+
### Pitfall
|
|
93
|
+
|
|
94
|
+
The `ts-morph` script above edits in-place. Commit your tree before running.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 2. Error-shape adapter
|
|
99
|
+
|
|
100
|
+
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
|
+
|
|
102
|
+
```ts
|
|
103
|
+
// shared/error-shape-adapter.ts
|
|
104
|
+
import { isSodaxError } from '@sodax/sdk';
|
|
105
|
+
|
|
106
|
+
export type V1ErrorShape = {
|
|
107
|
+
code?: string;
|
|
108
|
+
message?: string;
|
|
109
|
+
data?: { error?: unknown };
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Adapt v2 SodaxError onto the v1 `{ code, message, data: { error } }` shape so
|
|
114
|
+
* existing v1-style error helpers keep working without rewriting every branch.
|
|
115
|
+
*
|
|
116
|
+
* Migration only — replace with `(error.feature, error.code)` branching once the
|
|
117
|
+
* helper is rewritten.
|
|
118
|
+
*/
|
|
119
|
+
export function adaptToV1ErrorShape(error: unknown): V1ErrorShape | null {
|
|
120
|
+
if (error == null) return null;
|
|
121
|
+
|
|
122
|
+
// v2 SodaxError → v1-shaped object with code on top level.
|
|
123
|
+
if (isSodaxError(error)) {
|
|
124
|
+
return {
|
|
125
|
+
code: error.code,
|
|
126
|
+
message: error.message,
|
|
127
|
+
data: { error: error.cause },
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Plain Error (no code) — fall back to message.
|
|
132
|
+
if (error instanceof Error) {
|
|
133
|
+
return { code: error.message, message: error.message };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Already v1 shape — pass through.
|
|
137
|
+
if (typeof error === 'object') {
|
|
138
|
+
return error as V1ErrorShape;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Usage
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
// Before:
|
|
149
|
+
function getMmErrorText(error: unknown): string {
|
|
150
|
+
if (error instanceof MoneyMarketError) {
|
|
151
|
+
if (error.code === 'CREATE_SUPPLY_INTENT_FAILED') return 'Could not build supply';
|
|
152
|
+
if (error.code === 'SUPPLY_FAILED') return 'Supply failed';
|
|
153
|
+
}
|
|
154
|
+
return 'Unknown error';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// After (adapter at the top, branches keep working):
|
|
158
|
+
function getMmErrorText(error: unknown): string {
|
|
159
|
+
const sdkError = adaptToV1ErrorShape(error);
|
|
160
|
+
if (sdkError?.code === 'INTENT_CREATION_FAILED') return 'Could not build supply'; // v2 code
|
|
161
|
+
if (sdkError?.code === 'EXECUTION_FAILED') return 'Supply failed'; // v2 code
|
|
162
|
+
return 'Unknown error';
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Final-form (recommended)
|
|
167
|
+
|
|
168
|
+
After the adapter is in place, gradually rewrite each helper to use `(feature, code)` directly. The adapter is a stepping stone, not the destination:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
import { isSodaxError } from '@sodax/sdk';
|
|
172
|
+
|
|
173
|
+
function getMmErrorText(error: unknown): string {
|
|
174
|
+
if (!isSodaxError(error) || error.feature !== 'moneyMarket') return 'Unknown error';
|
|
175
|
+
switch (error.code) {
|
|
176
|
+
case 'INTENT_CREATION_FAILED':
|
|
177
|
+
return error.context?.action === 'supply' ? 'Could not build supply' : 'Could not build operation';
|
|
178
|
+
case 'EXECUTION_FAILED':
|
|
179
|
+
return `${error.context?.action ?? 'operation'} failed`;
|
|
180
|
+
case 'RELAY_TIMEOUT':
|
|
181
|
+
return 'Cross-chain relay timed out';
|
|
182
|
+
case 'TX_VERIFICATION_FAILED':
|
|
183
|
+
return 'Transaction could not be verified on the source chain';
|
|
184
|
+
default:
|
|
185
|
+
return 'Unexpected error';
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
See [`reference/error-code-crosswalk.md`](reference/error-code-crosswalk.md) for the full v1 → v2 code crosswalk and [`breaking-changes/result-and-errors.md`](breaking-changes/result-and-errors.md) § 6 for the discrimination patterns this snippet uses.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 3. Result adapter
|
|
195
|
+
|
|
196
|
+
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
|
+
|
|
198
|
+
```ts
|
|
199
|
+
// shared/result-adapter.ts
|
|
200
|
+
import { isSodaxError } from '@sodax/sdk';
|
|
201
|
+
import type { Result } from '@sodax/sdk';
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Throw on { ok: false }. v1-shape callers can `await throwIfError(result)` and
|
|
205
|
+
* keep their existing try/catch blocks during migration.
|
|
206
|
+
*
|
|
207
|
+
* The thrown value is the original error from the Result — typically a SodaxError.
|
|
208
|
+
* Existing instanceof / .code branches will still work via adaptToV1ErrorShape.
|
|
209
|
+
*
|
|
210
|
+
* Migration only — once the call site is converted to branch on result.ok directly,
|
|
211
|
+
* remove the throwIfError wrap.
|
|
212
|
+
*/
|
|
213
|
+
export function throwIfError<T>(result: Result<T, unknown>): T {
|
|
214
|
+
if (!result.ok) {
|
|
215
|
+
if (isSodaxError(result.error)) throw result.error;
|
|
216
|
+
if (result.error instanceof Error) throw result.error;
|
|
217
|
+
throw new Error(`unwrap failed: ${String(result.error)}`);
|
|
218
|
+
}
|
|
219
|
+
return result.value;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Same as throwIfError, but coerces non-Error errors to a thrown Error
|
|
224
|
+
* (useful when downstream code only catches Error).
|
|
225
|
+
*/
|
|
226
|
+
export function throwAsError<T>(result: Result<T, unknown>, fallbackMessage = 'operation failed'): T {
|
|
227
|
+
if (!result.ok) {
|
|
228
|
+
const e = result.error;
|
|
229
|
+
if (e instanceof Error) throw e;
|
|
230
|
+
throw new Error(typeof e === 'string' ? e : fallbackMessage);
|
|
231
|
+
}
|
|
232
|
+
return result.value;
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Usage during migration
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
// Before (v1):
|
|
240
|
+
try {
|
|
241
|
+
const txHash = await sodax.moneyMarket.supply({ params, spokeProvider });
|
|
242
|
+
/* … */
|
|
243
|
+
} catch (e) {
|
|
244
|
+
if (e instanceof MoneyMarketError && e.code === 'SUPPLY_FAILED') /* … */
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// During migration (with shim):
|
|
248
|
+
try {
|
|
249
|
+
const { srcChainTxHash } = await throwIfError(
|
|
250
|
+
await sodax.moneyMarket.supply({ params, raw: false, walletProvider }),
|
|
251
|
+
);
|
|
252
|
+
/* … */
|
|
253
|
+
} catch (e) {
|
|
254
|
+
// existing v1-shape branches keep working via adaptToV1ErrorShape;
|
|
255
|
+
// SodaxError instances satisfy the same checks once you migrate them
|
|
256
|
+
if (e instanceof Error && /* … */) /* … */
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Final-form (recommended)
|
|
261
|
+
|
|
262
|
+
Once the call site is converted, drop `throwIfError`:
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
const result = await sodax.moneyMarket.supply({ params, raw: false, walletProvider });
|
|
266
|
+
if (!result.ok) {
|
|
267
|
+
setError(getMmErrorText(result.error));
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const { srcChainTxHash } = result.value;
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Pitfall — the v1-style `try { await sodax.<method>(...) } catch` does not work
|
|
274
|
+
|
|
275
|
+
A common mistake during migration: keeping the `try/catch` block but updating the inner call to v2 shape, expecting it to still throw. **It won't.** v2 `Result<T>` resolves on failure — the `catch` only fires for synchronous wrapper exceptions (e.g. missing `walletProvider`). Either:
|
|
276
|
+
|
|
277
|
+
- Wrap the call in `throwIfError` (this recipe), so failures throw.
|
|
278
|
+
- Branch on `result.ok` (preferred end state).
|
|
279
|
+
|
|
280
|
+
Don't leave the `try/catch` in place expecting it to catch SDK-level failures — it can't.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Cross-references
|
|
285
|
+
|
|
286
|
+
- The breaking changes that motivate these recipes: [`breaking-changes/type-system.md`](breaking-changes/type-system.md), [`breaking-changes/architecture.md`](breaking-changes/architecture.md), [`breaking-changes/result-and-errors.md`](breaking-changes/result-and-errors.md).
|
|
287
|
+
- Per-feature playbooks (which assume these recipes are in your toolkit): [`features/`](features/).
|
|
288
|
+
- v2 design context (the patterns you're migrating *to*): [`../integration/recipes/`](../integration/recipes/).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Migration reference — `@sodax/sdk` v1 → v2
|
|
2
|
+
|
|
3
|
+
Tables. Each file is a focused lookup; the prose explanations live in `../breaking-changes/` and `../features/`.
|
|
4
|
+
|
|
5
|
+
| File | Contents |
|
|
6
|
+
|---|---|
|
|
7
|
+
| [`deleted-exports.md`](deleted-exports.md) | Comprehensive table of every removed v1 export with its v2 replacement: spoke-provider classes & guards, static lookup tables, type aliases, constants, error types, per-feature param-shape changes. |
|
|
8
|
+
| [`sodax-config.md`](sodax-config.md) | `SodaxConfig` constructor reshape: `swaps` vs `solver` field split, `rpcConfig` keying change, `hubProviderConfig` → `hubConfig` rename, `configService` injection point gone. |
|
|
9
|
+
| [`error-code-crosswalk.md`](error-code-crosswalk.md) | Per-feature v1 module-error code → v2 `(feature, code, context)` tuple. Money market, swap, staking, bridge, migration, DEX, relay, partner, recovery. |
|
|
10
|
+
| [`return-shapes.md`](return-shapes.md) | Per-method return-shape diffs. `CreateIntentResult` tuple→object, every cross-chain mutation now returns `TxHashPair`, `getBridgeableAmount` returns `BridgeLimit`, `getStakeRatio` returns a tuple, etc. |
|
|
11
|
+
|
|
12
|
+
## Cross-references
|
|
13
|
+
|
|
14
|
+
- [`../README.md`](../README.md) — migration overview.
|
|
15
|
+
- [`../checklist.md`](../checklist.md) — top-level migration checklist.
|
|
16
|
+
- [`../ai-rules.md`](../ai-rules.md) — DO / DO NOT / workflow.
|
|
17
|
+
- [`../breaking-changes/`](../breaking-changes/) — the prose that explains what these tables tabulate.
|
|
18
|
+
- v2 design context: [`../../integration/architecture.md`](../../integration/architecture.md) and [`../../integration/reference/`](../../integration/reference/).
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Deleted exports inventory
|
|
2
|
+
|
|
3
|
+
Every v1 export removed from `@sodax/sdk` and `@sodax/types`, with its v2 replacement. If you see `error TS2305: Module '"@sodax/sdk"' has no exported member '<X>'`, find `<X>` in the left column.
|
|
4
|
+
|
|
5
|
+
### Spoke-provider classes + guards
|
|
6
|
+
|
|
7
|
+
| v1 export | v2 replacement |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `EvmSpokeProvider` (class) | None — pass `walletProvider` + `srcChainKey` to SDK calls. See [`../breaking-changes/architecture.md`](../breaking-changes/architecture.md) § 1. |
|
|
10
|
+
| `SonicSpokeProvider` (class) | Same. |
|
|
11
|
+
| `SolanaSpokeProvider` (class) | Same. |
|
|
12
|
+
| `SuiSpokeProvider` (class) | Same. |
|
|
13
|
+
| `IconSpokeProvider` (class) | Same. |
|
|
14
|
+
| `InjectiveSpokeProvider` (class) | Same. |
|
|
15
|
+
| `StellarSpokeProvider` / `StellarBaseSpokeProvider` (classes) | Same. |
|
|
16
|
+
| `StacksSpokeProvider` (class) | Same. |
|
|
17
|
+
| `BitcoinSpokeProvider` (class) | Same. |
|
|
18
|
+
| `NearSpokeProvider` (class) | Same. |
|
|
19
|
+
| `SpokeProvider` (union type) | None — broad-union typing replaced by `srcChainKey: SpokeChainKey` + `walletProvider: GetWalletProviderType<K>`. |
|
|
20
|
+
| `isEvmSpokeProvider`, `isSolanaSpokeProvider`, `isBitcoinSpokeProvider`, `isStellarSpokeProvider`, `isIconSpokeProvider`, `isSuiSpokeProvider`, `isInjectiveSpokeProvider`, `isStacksSpokeProvider`, `isNearSpokeProvider`, `isSonicSpokeProvider` | `getChainType(chainKey) === '<FAMILY>'`, or family-level `is<Family>ChainKeyType(chainKey)` from `@sodax/sdk`. See [`../breaking-changes/architecture.md`](../breaking-changes/architecture.md) § 1. |
|
|
21
|
+
|
|
22
|
+
### Static lookup tables and helpers
|
|
23
|
+
|
|
24
|
+
| v1 export | v2 replacement |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `hubAssets` | `XToken.vault` / `XToken.hubAsset` baked in; or `sodax.config.getOriginalAssetAddress(...)`. See [`../breaking-changes/architecture.md`](../breaking-changes/architecture.md) § 2. |
|
|
27
|
+
| `moneyMarketSupportedTokens` | `sodax.moneyMarket.getSupportedTokensByChainId(chainKey)` / `getSupportedTokens()`. |
|
|
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()`. |
|
|
31
|
+
| `EvmWalletAbstraction` (class) | `sodax.hubProvider.getUserHubWalletAddress(...)` (the equivalent functionality lives on `EvmHubProvider`, accessed via the `Sodax` instance). |
|
|
32
|
+
|
|
33
|
+
### Type aliases
|
|
34
|
+
|
|
35
|
+
| v1 export | v2 replacement |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `ChainId` (type) | `SpokeChainKey` (or `ChainKey` for the broader union including the hub). |
|
|
38
|
+
| `SpokeChainId` (type) | `SpokeChainKey`. |
|
|
39
|
+
| `EvmChainId` (type) | `EvmChainKey` (subset of `SpokeChainKey`). |
|
|
40
|
+
| `HubChainId` (type) | `HubChainKey` (literal `'sonic'`). |
|
|
41
|
+
| `Token` (type) | `XToken`. See [`../breaking-changes/type-system.md`](../breaking-changes/type-system.md) § 4. |
|
|
42
|
+
| `AddressType` (type) | `BtcAddressType`. See [`../breaking-changes/type-system.md`](../breaking-changes/type-system.md) § 7. |
|
|
43
|
+
| `BtcWalletAddressType` (type) | `BtcAddressType` (cleaned-up name). |
|
|
44
|
+
| `Payload` (type) | None — internal `IntentRelayApiService` shape that v1 leaked publicly. Consumers calling the relay layer directly should use `relayTxAndWaitPacket` / `submitTransaction` (which take typed inputs). |
|
|
45
|
+
|
|
46
|
+
### Constants
|
|
47
|
+
|
|
48
|
+
| v1 export | v2 replacement |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `*_MAINNET_CHAIN_ID` (20 constants) | `ChainKeys.*` (single namespace). See [`../breaking-changes/type-system.md`](../breaking-changes/type-system.md) § 1 for the full table. |
|
|
51
|
+
|
|
52
|
+
### Wallet shims
|
|
53
|
+
|
|
54
|
+
| v1 export | v2 replacement |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `CustomProvider` (Hana-wallet window typedecl) | None. Window declaration becomes `unknown` or imports directly from the wallet vendor. Low-level Hana-extension helper functions (`requestAddress`, `requestSigning`, `requestJsonRpc`) ship from `@sodax/sdk` for consumers building their own Hana-based `IIconWalletProvider`. |
|
|
57
|
+
|
|
58
|
+
### Error types and guards
|
|
59
|
+
|
|
60
|
+
| v1 export | v2 replacement |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `MoneyMarketError<MoneyMarketErrorCode>`, plus `MoneyMarketErrorCode` | `SodaxError<C>` with `feature: 'moneyMarket'`. See [`error-code-crosswalk.md`](error-code-crosswalk.md) for code crosswalk. |
|
|
63
|
+
| `IntentError<IntentErrorCode>`, plus the union | `SodaxError<C>` with `feature: 'swap'`. |
|
|
64
|
+
| `StakingError<StakingErrorCode>`, plus the union | `SodaxError<C>` with `feature: 'staking'`. |
|
|
65
|
+
| `BridgeError<BridgeErrorCode>`, plus the union | `SodaxError<C>` with `feature: 'bridge'`. |
|
|
66
|
+
| `MigrationError<MigrationErrorCode>`, plus the union | `SodaxError<C>` with `feature: 'migration'`. |
|
|
67
|
+
| `AssetServiceError<AssetServiceErrorCode>`, plus the union | `SodaxError<C>` with `feature: 'dex'`. |
|
|
68
|
+
| `ConcentratedLiquidityError<ConcentratedLiquidityErrorCode>`, plus the union | `SodaxError<C>` with `feature: 'dex'`. |
|
|
69
|
+
| `RelayError<RelayErrorCode>`, plus the union | `SodaxError<C>` with relay code on `error.context.relayCode`. |
|
|
70
|
+
| `PartnerFeeClaimError<...>` (5 partner errors) | `SodaxError<C>` with `feature: 'partner'`. |
|
|
71
|
+
| `isMoneyMarketError`, `isIntentError`, `isStakingError`, `isBridgeError`, `isMigrationError`, `isAssetServiceError`, `isConcentratedLiquidityError`, `isRelayError` (type-guards) | `isSodaxError(e)` + check `e.feature === '<feature>'`, or use `isFeatureError('<feature>')` to build a guard. See [`../breaking-changes/result-and-errors.md`](../breaking-changes/result-and-errors.md) § 6 for migration patterns. |
|
|
72
|
+
| `isIntentPostExecutionFailedError(e)` | `isSodaxError(e) && e.feature === 'swap' && e.code === 'EXECUTION_FAILED' && e.context?.phase === 'postExecution'`. |
|
|
73
|
+
| `isIntentSubmitTxFailedError(e)` | `isSodaxError(e) && e.code === 'TX_SUBMIT_FAILED'`. |
|
|
74
|
+
|
|
75
|
+
### Per-feature param shape
|
|
76
|
+
|
|
77
|
+
These types changed shape (typically: gained a generic `<K extends SpokeChainKey>`, gained `srcChainKey` and `srcAddress` required fields). The v1 names still exist but with a different signature — fixing imports won't compile, you also need to update construction.
|
|
78
|
+
|
|
79
|
+
| v1 type | v2 type | Required additions in v2 |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `MoneyMarketSupplyParams` | `MoneyMarketSupplyParams<K extends SpokeChainKey>` | `srcChainKey: K`, `srcAddress: GetAddressType<K>` |
|
|
82
|
+
| `MoneyMarketBorrowParams` | `MoneyMarketBorrowParams<K>` | Same; plus optional `dstChainKey`, `dstAddress` for cross-chain. |
|
|
83
|
+
| `MoneyMarketWithdrawParams` | `MoneyMarketWithdrawParams<K>` | Same. |
|
|
84
|
+
| `MoneyMarketRepayParams` | `MoneyMarketRepayParams<K>` | Same; plus optional `dstChainKey`/`dstAddress` (debt chain). |
|
|
85
|
+
| `StakeParams`, `UnstakeParams`, `InstantUnstakeParams`, `ClaimParams`, `CancelUnstakeParams` | All gained `<K>` generic | `srcChainKey: K`, `srcAddress: GetAddressType<K>`. v1 `account` field renamed to `srcAddress`. |
|
|
86
|
+
| `MigrationParams` | `MigrationParams<K>` | Same. |
|
|
87
|
+
| `UnifiedBnUSDMigrateParams` | `UnifiedBnUSDMigrateParams<K>` | Same. |
|
|
88
|
+
| `CreateAssetDepositParams`, `CreateAssetWithdrawParams`, `ClSupplyParams`, `ClIncreaseLiquidityParams`, `ClDecreaseLiquidityParams`, `ClClaimRewardsParams` | All gained `<K>` generic | `srcChainKey`, `srcAddress`. |
|
|
89
|
+
| `CreateIntentParams`, `CreateLimitOrderParams` | All gained `<K>` generic | Field renames `srcChain` → `srcChainKey`, `dstChain` → `dstChainKey` (v1 `srcChain` was a chain id type, now `srcChainKey: K`). |
|
|
90
|
+
|
|
91
|
+
The [`error TS1360`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-2.html#smarter-type-alias-preservation) pattern (`Type '{ token, amount, action }' does not satisfy the expected type 'MoneyMarketSupplyParams'`) is the typecheck signature: a literal that matches v1's shape but missing v2's required `srcChainKey` and `srcAddress`. Add both.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
## Cross-references
|
|
97
|
+
|
|
98
|
+
- [`README.md`](README.md) — migration reference index.
|
|
99
|
+
- [`../README.md`](../README.md) — migration overview.
|
|
100
|
+
- [`../checklist.md`](../checklist.md) — top-level migration checklist.
|