@sodax/sdk 1.5.7-beta → 2.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +91 -7
  2. package/ai-exported/AGENTS.md +99 -0
  3. package/ai-exported/integration/README.md +41 -0
  4. package/ai-exported/integration/ai-rules.md +75 -0
  5. package/ai-exported/integration/architecture.md +519 -0
  6. package/ai-exported/integration/chain-specifics.md +189 -0
  7. package/ai-exported/integration/features/README.md +19 -0
  8. package/ai-exported/integration/features/auxiliary-services.md +189 -0
  9. package/ai-exported/integration/features/bridge.md +136 -0
  10. package/ai-exported/integration/features/dex.md +182 -0
  11. package/ai-exported/integration/features/icx-bnusd-baln.md +181 -0
  12. package/ai-exported/integration/features/money-market.md +198 -0
  13. package/ai-exported/integration/features/staking.md +166 -0
  14. package/ai-exported/integration/features/swap.md +207 -0
  15. package/ai-exported/integration/quickstart.md +213 -0
  16. package/ai-exported/integration/recipes/README.md +21 -0
  17. package/ai-exported/integration/recipes/backend-server-init.md +69 -0
  18. package/ai-exported/integration/recipes/chain-key-narrowing.md +65 -0
  19. package/ai-exported/integration/recipes/gas-estimation.md +33 -0
  20. package/ai-exported/integration/recipes/initialize-sodax.md +53 -0
  21. package/ai-exported/integration/recipes/raw-tx-flow.md +71 -0
  22. package/ai-exported/integration/recipes/result-and-errors.md +104 -0
  23. package/ai-exported/integration/recipes/signed-tx-flow.md +46 -0
  24. package/ai-exported/integration/recipes/testing.md +101 -0
  25. package/ai-exported/integration/reference/README.md +18 -0
  26. package/ai-exported/integration/reference/chain-keys.md +67 -0
  27. package/ai-exported/integration/reference/error-codes.md +165 -0
  28. package/ai-exported/integration/reference/glossary.md +32 -0
  29. package/ai-exported/integration/reference/public-api.md +138 -0
  30. package/ai-exported/integration/reference/wallet-providers.md +62 -0
  31. package/ai-exported/migration/README.md +58 -0
  32. package/ai-exported/migration/ai-rules.md +80 -0
  33. package/ai-exported/migration/breaking-changes/architecture.md +342 -0
  34. package/ai-exported/migration/breaking-changes/result-and-errors.md +363 -0
  35. package/ai-exported/migration/breaking-changes/type-system.md +321 -0
  36. package/ai-exported/migration/checklist.md +61 -0
  37. package/ai-exported/migration/features/README.md +35 -0
  38. package/ai-exported/migration/features/auxiliary-services.md +156 -0
  39. package/ai-exported/migration/features/bridge.md +125 -0
  40. package/ai-exported/migration/features/dex.md +143 -0
  41. package/ai-exported/migration/features/icx-bnusd-baln.md +151 -0
  42. package/ai-exported/migration/features/money-market.md +214 -0
  43. package/ai-exported/migration/features/staking.md +138 -0
  44. package/ai-exported/migration/features/swap.md +198 -0
  45. package/ai-exported/migration/recipes.md +288 -0
  46. package/ai-exported/migration/reference/README.md +18 -0
  47. package/ai-exported/migration/reference/deleted-exports.md +126 -0
  48. package/ai-exported/migration/reference/error-code-crosswalk.md +104 -0
  49. package/ai-exported/migration/reference/return-shapes.md +49 -0
  50. package/ai-exported/migration/reference/sodax-config.md +52 -0
  51. package/dist/index.cjs +32076 -31544
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.d.cts +8604 -7136
  54. package/dist/index.d.ts +8604 -7136
  55. package/dist/index.mjs +31893 -31402
  56. package/dist/index.mjs.map +1 -1
  57. package/package.json +20 -12
@@ -0,0 +1,182 @@
1
+ # DEX — `DexService` (`AssetService` + `ClService`)
2
+
3
+ Concentrated liquidity AMM, similar to Uniswap V3 / PancakeSwap V3. Two sub-services:
4
+
5
+ - **`AssetService`** — wraps/unwraps spoke assets into the hub-side pool tokens. `deposit` (spoke→hub), `withdraw` (hub→spoke).
6
+ - **`ClService`** — full concentrated-liquidity position lifecycle: mint, increase, decrease, claim rewards. Pool / position read methods. (Class lives in `ConcentratedLiquidityService.ts` but the exported class is named `ClService`.)
7
+
8
+ Access: `sodax.dex.assetService`, `sodax.dex.clService`. Class names: `AssetService`, `ClService`. Feature tag for errors: `'dex'`.
9
+
10
+ ## How it works
11
+
12
+ To enter a position:
13
+
14
+ 1. **`assetService.deposit({ asset, amount, poolToken, ... })`** — wraps the spoke token into the hub-side pool token (vault).
15
+ 2. **`assetService.approve(...)`** — permit the CL contract to spend the wrapped token.
16
+ 3. **`clService.supplyLiquidity({ poolKey, ..., liquidity, amount0Max, amount1Max })`** — mints a new position NFT.
17
+
18
+ To increase / decrease / claim:
19
+
20
+ - **`clService.increaseLiquidity({ tokenId, ... })`** — adds liquidity to an existing position.
21
+ - **`clService.decreaseLiquidity({ tokenId, liquidity, amount0Min, amount1Min })`** — removes a fraction of liquidity (no NFT burn).
22
+ - **`clService.claimRewards({ tokenId, poolKey, tickLower, tickUpper })`** — collects accrued fees/rewards for a position.
23
+
24
+ ## Public methods
25
+
26
+ ```ts
27
+ // AssetService
28
+ sodax.dex.assetService.deposit<K>(action: AssetDepositAction<K, false>): Promise<Result<TxHashPair, SodaxError>>;
29
+ sodax.dex.assetService.withdraw<K>(action: AssetWithdrawAction<K, false>): Promise<Result<TxHashPair, SodaxError>>;
30
+ sodax.dex.assetService.approve<K, Raw>(args): Promise<Result<TxReturnType<K, Raw>, SodaxError>>;
31
+ sodax.dex.assetService.isAllowanceValid<K, Raw>(args): Promise<Result<boolean, SodaxError>>;
32
+ sodax.dex.assetService.getDeposit(poolToken, walletAddress, chainKey): Promise<Result<bigint, SodaxError>>;
33
+ sodax.dex.assetService.executeDeposit<K, Raw>(args): /* spoke-only deposit; no relay */;
34
+
35
+ // ClService (concentrated liquidity)
36
+ sodax.dex.clService.supplyLiquidity<K>(action): Promise<Result<TxHashPair, SodaxError>>;
37
+ sodax.dex.clService.increaseLiquidity<K>(action): Promise<Result<TxHashPair, SodaxError>>;
38
+ sodax.dex.clService.decreaseLiquidity<K>(action): Promise<Result<TxHashPair, SodaxError>>;
39
+ sodax.dex.clService.claimRewards<K>(action): Promise<Result<TxHashPair, SodaxError>>;
40
+
41
+ sodax.dex.clService.getPools(): PoolKey[]; // synchronous in v2
42
+ sodax.dex.clService.getPoolData(poolKey, publicClient): Promise<Result<PoolData, SodaxError>>;
43
+ sodax.dex.clService.getPositionInfo(tokenId, poolKey, publicClient): Promise<Result<PositionInfo, SodaxError>>;
44
+ sodax.dex.clService.getAssetsForPool(srcChainKey, poolKey): { token0, token1 }; // chain-key-first; sync
45
+
46
+ // Static math helpers (still throw on error — utility class):
47
+ ClService.priceToTick(price): number;
48
+ ClService.calculateAmount0FromAmount1(...): bigint;
49
+ ClService.calculateAmount1FromAmount0(...): bigint;
50
+ ```
51
+
52
+ ## Action params shape
53
+
54
+ ```ts
55
+ type CreateAssetDepositParams<K extends SpokeChainKey> = {
56
+ srcChainKey: K;
57
+ srcAddress: GetAddressType<K>;
58
+ asset: `0x${string}`; // spoke-side token address
59
+ amount: bigint;
60
+ poolToken: `0x${string}`; // hub-side pool token (vault address)
61
+ dst?: { chainKey: SpokeChainKey; address: string }; // optional cross-chain delivery
62
+ };
63
+
64
+ type CreateAssetWithdrawParams<K> = { /* same shape */ };
65
+
66
+ type ClSupplyParams<K> = {
67
+ srcChainKey: K;
68
+ srcAddress: GetAddressType<K>;
69
+ poolKey: PoolKey;
70
+ tickLower: number;
71
+ tickUpper: number;
72
+ liquidity: bigint;
73
+ amount0Max: bigint;
74
+ amount1Max: bigint;
75
+ sqrtPriceX96: bigint;
76
+ };
77
+
78
+ type ClIncreaseLiquidityParams<K> = ClSupplyParams<K> & { tokenId: bigint };
79
+ type ClDecreaseLiquidityParams<K> = {
80
+ srcChainKey: K;
81
+ srcAddress: GetAddressType<K>;
82
+ poolKey: PoolKey;
83
+ tokenId: bigint;
84
+ liquidity: bigint;
85
+ amount0Min: bigint;
86
+ amount1Min: bigint;
87
+ };
88
+ type ClClaimRewardsParams<K> = { srcChainKey, srcAddress, poolKey, tokenId, tickLower, tickUpper };
89
+ ```
90
+
91
+ ## Common call shapes
92
+
93
+ ### Deposit (spoke asset → hub pool token)
94
+
95
+ ```ts
96
+ const result = await sodax.dex.assetService.deposit({
97
+ params: {
98
+ srcChainKey: ChainKeys.ARBITRUM_MAINNET,
99
+ srcAddress: '0x…',
100
+ asset: USDC.address,
101
+ amount: parseUnits('100', 6),
102
+ poolToken: '0x…', // the hub-side pool token (XToken.vault)
103
+ },
104
+ raw: false,
105
+ walletProvider: evmWp,
106
+ });
107
+
108
+ if (!result.ok) return;
109
+ const { srcChainTxHash, dstChainTxHash } = result.value;
110
+ ```
111
+
112
+ ### Mint a new concentrated-liquidity position
113
+
114
+ ```ts
115
+ const result = await sodax.dex.clService.supplyLiquidity({
116
+ params: {
117
+ srcChainKey: ChainKeys.ARBITRUM_MAINNET,
118
+ srcAddress: '0x…',
119
+ poolKey: { /* { currency0, currency1, fee, tickSpacing, hooks } */ },
120
+ tickLower: -887220,
121
+ tickUpper: 887220,
122
+ liquidity: 1000000n,
123
+ amount0Max: parseUnits('100', 6),
124
+ amount1Max: parseUnits('100', 6),
125
+ sqrtPriceX96: /* current sqrtPrice */,
126
+ },
127
+ raw: false,
128
+ walletProvider: evmWp,
129
+ });
130
+ ```
131
+
132
+ ### Increase liquidity on an existing position
133
+
134
+ ```ts
135
+ await sodax.dex.clService.increaseLiquidity({
136
+ params: { /* same as supplyLiquidity, plus tokenId: existingPositionTokenId */ },
137
+ raw: false,
138
+ walletProvider: evmWp,
139
+ });
140
+ ```
141
+
142
+ ### Allowance check (read-only)
143
+
144
+ ```ts
145
+ const allowed = await sodax.dex.assetService.isAllowanceValid({
146
+ params: { srcChainKey, srcAddress, asset, amount, poolToken },
147
+ raw: true, // read-only — no walletProvider required
148
+ });
149
+ ```
150
+
151
+ The underlying read does not consult the wallet provider; pass `raw: true` to satisfy `WalletProviderSlot` without supplying a provider.
152
+
153
+ ## Return shapes
154
+
155
+ | Method | Success type |
156
+ |---|---|
157
+ | `deposit`, `withdraw`, `supplyLiquidity`, `increaseLiquidity`, `decreaseLiquidity`, `claimRewards` | `TxHashPair` |
158
+ | `approve` | `TxReturnType<K, Raw>` |
159
+ | `isAllowanceValid` | `boolean` |
160
+ | `getDeposit` | `bigint` (user's balance in the pool's hub wallet) |
161
+ | `getPoolData` | `{ liquidity, sqrtPriceX96, tick, /* … */ }` |
162
+ | `getPositionInfo` | `{ poolKey, tickLower, tickUpper, liquidity, fees0, fees1, /* … */ }` |
163
+ | `getPools` | `PoolKey[]` (synchronous, returns from cached config) |
164
+ | `getAssetsForPool` | `{ token0: XToken, token1: XToken }` (synchronous; takes `srcChainKey` to filter by spoke availability) |
165
+
166
+ > `getPools()` is **synchronous** in v2 (was `Promise<PoolKey[]>` in v1). v2 reads from cached config — no I/O. `await sodax.dex.clService.getPools()` works (TS allows `await` on non-promise) but `.then(...)` is a runtime error.
167
+
168
+ ## Error codes
169
+
170
+ `feature: 'dex'`. Per-method narrow unions:
171
+
172
+ | Method | Codes | Action |
173
+ |---|---|---|
174
+ | `deposit`, `withdraw`, `supplyLiquidity`, `increaseLiquidity`, `decreaseLiquidity`, `claimRewards` | full exec set | matches operation |
175
+ | `approve` | `VALIDATION_FAILED`, `APPROVE_FAILED`, `UNKNOWN` | matches operation |
176
+ | `isAllowanceValid` | `VALIDATION_FAILED`, `ALLOWANCE_CHECK_FAILED`, `UNKNOWN` | n/a |
177
+ | `getDeposit`, `getPoolData`, `getPositionInfo` | `VALIDATION_FAILED`, `LOOKUP_FAILED`, `UNKNOWN` | (use `error.context.method`) |
178
+
179
+ ## Cross-references
180
+
181
+ - v1 → v2 DEX migration: [`../../migration/features/dex.md`](../../migration/features/dex.md).
182
+ - The hub-side `EvmHubProvider.publicClient` is what `getPoolData` / `getPositionInfo` use internally — consumers can pass `sodax.hubProvider.publicClient`.
@@ -0,0 +1,181 @@
1
+ # Token migration — `MigrationService`
2
+
3
+ Migration of legacy ICON ecosystem tokens to the SODAX hub. Three sub-services:
4
+
5
+ - **`IcxMigrationService`** — ICX/wICX → SODA (forward) and SODA → ICX (revert).
6
+ - **`BnUSDMigrationService`** — legacy bnUSD (ICON / Sui / Stellar) ↔ new bnUSD (EVM chains) via vault transformations.
7
+ - **`BalnSwapService`** — BALN → SODA with lockup periods (0–24 months) that multiply rewards (0.5x–1.5x).
8
+
9
+ Access: `sodax.migration`. Service class: `MigrationService` (with sub-services `sodax.migration.icxMigration`, `sodax.migration.bnUSDMigrationService`, `sodax.migration.balnSwapService`). Feature tag for errors: `'migration'`.
10
+
11
+ > Don't confuse this feature (the `MigrationService` SDK module) with the v1 → v2 SDK port itself. They share the word "migration" but are independent concerns. The v1 → v2 port playbook lives at [`../../migration/features/icx-bnusd-baln.md`](../../migration/features/icx-bnusd-baln.md).
12
+
13
+ ## How it works
14
+
15
+ All three sub-services follow the same pattern: deposit on a spoke chain → relay to hub → execute hub-side migration contract → deliver new token.
16
+
17
+ `MigrationService` exposes 11 async public methods:
18
+
19
+ - 4 orchestrators (full execution): `migratebnUSD`, `migrateIcxToSoda`, `revertMigrateSodaToIcx`, `migrateBaln`.
20
+ - 4 intent creators (raw or signed spoke tx, no full lifecycle): `createMigrateBnUSDIntent`, `createMigrateIcxToSodaIntent`, `createRevertMigrateSodaToIcxIntent`, `createMigrateBalnIntent`.
21
+ - `approve`, `isAllowanceValid` (action-discriminated like staking and money market).
22
+ - `getAvailableAmount` (read-only; `IcxMigrationService` only — checks how much SODA the user can claim from a partial migration).
23
+
24
+ `BalnSwapService` has additional lock-management methods that **still throw** (do not return `Result<T>`): `claim`, `claimUnstaked`, `stake`, `unstake`, `cancelUnstake`, `getDetailedUserLocks`. This is deliberate tech debt; future cleanup. Wrap them in `try/catch` until then.
25
+
26
+ ## Public methods
27
+
28
+ ```ts
29
+ sodax.migration.migratebnUSD<K>(action): Promise<Result<TxHashPair, SodaxError>>;
30
+ sodax.migration.migrateIcxToSoda<K>(action): Promise<Result<TxHashPair, SodaxError>>;
31
+ sodax.migration.revertMigrateSodaToIcx<K>(action): Promise<Result<TxHashPair, SodaxError>>;
32
+ sodax.migration.migrateBaln<K>(action): Promise<Result<TxHashPair, SodaxError>>;
33
+
34
+ sodax.migration.createMigrateBnUSDIntent<K, Raw>(...): Promise<Result<...>>;
35
+ // + 3 other createXxxIntent methods
36
+
37
+ sodax.migration.approve<K, Raw>(args): Promise<Result<TxReturnType<K, Raw>, SodaxError>>;
38
+ sodax.migration.isAllowanceValid<K, Raw>(args): Promise<Result<boolean, SodaxError>>;
39
+
40
+ sodax.migration.icxMigration.getAvailableAmount(): Promise<Result<bigint, SodaxError>>;
41
+
42
+ // BalnSwapService — STILL THROW (tech debt; not Result-wrapped):
43
+ sodax.migration.balnSwapService.claim(...): Promise<TxReturnType<K, false>>;
44
+ sodax.migration.balnSwapService.claimUnstaked(...): Promise<TxReturnType<K, false>>;
45
+ sodax.migration.balnSwapService.stake(...): Promise<TxReturnType<K, false>>;
46
+ sodax.migration.balnSwapService.unstake(...): Promise<TxReturnType<K, false>>;
47
+ sodax.migration.balnSwapService.cancelUnstake(...): Promise<TxReturnType<K, false>>;
48
+ sodax.migration.balnSwapService.getDetailedUserLocks(...): Promise<DetailedUserLocks>;
49
+ ```
50
+
51
+ ## Action params shape
52
+
53
+ ```ts
54
+ type MigrationParams<K extends SpokeChainKey> = {
55
+ srcChainKey: K;
56
+ srcAddress: GetAddressType<K>;
57
+ amount: bigint;
58
+ dstAddress?: string;
59
+ };
60
+
61
+ type UnifiedBnUSDMigrateParams<K> = MigrationParams<K> & {
62
+ srcToken: `0x${string}`; // legacy or new bnUSD; SDK detects direction from address
63
+ dstToken: `0x${string}`; // the other side
64
+ };
65
+
66
+ type IcxToSodaMigrateParams<K> = MigrationParams<K>;
67
+ type RevertSodaToIcxParams<K> = MigrationParams<K>;
68
+ type BalnSwapParams<K> = MigrationParams<K> & {
69
+ lockPeriodMonths: 0 | 1 | 2 | 3 | 6 | 12 | 18 | 24; // reward multiplier 0.5x – 1.5x
70
+ };
71
+ ```
72
+
73
+ ## Common call shapes
74
+
75
+ ### bnUSD migrate (forward — legacy → new, e.g. ICON → BASE)
76
+
77
+ ```ts
78
+ const result = await sodax.migration.migratebnUSD({
79
+ params: {
80
+ srcChainKey: ChainKeys.ICON_MAINNET,
81
+ srcAddress: 'hx…',
82
+ srcToken: '0x…', // legacy bnUSD on ICON
83
+ dstToken: '0x…', // new bnUSD on BASE
84
+ amount: parseUnits('100', 18),
85
+ dstAddress: '0x…',
86
+ },
87
+ raw: false,
88
+ walletProvider: iconWp,
89
+ });
90
+
91
+ if (!result.ok) return;
92
+ const { srcChainTxHash, dstChainTxHash } = result.value;
93
+ ```
94
+
95
+ The SDK auto-detects direction from `(srcToken, dstToken)` addresses; the `direction` field surfaces on `error.context` if it fails (`'forward' | 'reverse'`).
96
+
97
+ ### ICX → SODA
98
+
99
+ ```ts
100
+ await sodax.migration.migrateIcxToSoda({
101
+ params: { srcChainKey: ChainKeys.ICON_MAINNET, srcAddress: 'hx…', amount },
102
+ raw: false,
103
+ walletProvider: iconWp,
104
+ });
105
+ ```
106
+
107
+ ### Revert SODA → ICX
108
+
109
+ ```ts
110
+ await sodax.migration.revertMigrateSodaToIcx({
111
+ params: { srcChainKey: ChainKeys.SONIC_MAINNET, srcAddress: '0x…', amount },
112
+ raw: false,
113
+ walletProvider: sonicWp,
114
+ });
115
+ ```
116
+
117
+ ### BALN → SODA with lockup
118
+
119
+ ```ts
120
+ await sodax.migration.migrateBaln({
121
+ params: {
122
+ srcChainKey: ChainKeys.ICON_MAINNET,
123
+ srcAddress: 'hx…',
124
+ amount: parseUnits('1000', 18),
125
+ lockPeriodMonths: 12, // 1.0x base; 24 is 1.5x; 0 is 0.5x
126
+ },
127
+ raw: false,
128
+ walletProvider: iconWp,
129
+ });
130
+ ```
131
+
132
+ ### Approve / allowance — action-discriminated
133
+
134
+ ```ts
135
+ await sodax.migration.approve({
136
+ params: { srcChainKey, srcAddress, amount, action: 'migratebnUSD' /* or 'migrateIcxToSoda' | 'revertMigrateSodaToIcx' | 'migrateBaln' */ },
137
+ raw: false,
138
+ walletProvider,
139
+ });
140
+ ```
141
+
142
+ ### BALN lock management (carve-out — still throws)
143
+
144
+ ```ts
145
+ try {
146
+ const tx = await sodax.migration.balnSwapService.stake({ /* … */ });
147
+ } catch (e) {
148
+ // Handle as v1-style throw. Result wrapping for these methods is on the roadmap.
149
+ }
150
+ ```
151
+
152
+ ## Return shapes
153
+
154
+ | Method | Success type |
155
+ |---|---|
156
+ | 4 orchestrators (`migratebnUSD`, `migrateIcxToSoda`, `revertMigrateSodaToIcx`, `migrateBaln`) | `TxHashPair` |
157
+ | 4 intent creators | `CreateIntentResult<K, Raw>` |
158
+ | `approve` | `TxReturnType<K, Raw>` |
159
+ | `isAllowanceValid` | `boolean` |
160
+ | `getAvailableAmount` | `bigint` |
161
+ | `BalnSwapService.claim` etc. | `TxReturnType<K, false>` (raw, not `Result`-wrapped) |
162
+
163
+ ## Error codes
164
+
165
+ `feature: 'migration'`. Per-method narrow unions:
166
+
167
+ | Method | Codes | `error.context.action` | Notes |
168
+ |---|---|---|---|
169
+ | `migratebnUSD` | full exec set incl. `TX_VERIFICATION_FAILED` | `'migratebnUSD'` | `error.context.direction: 'forward' \| 'reverse'`. Has secondary `phase: 'destinationExecution'` for the bnUSD `waitUntilIntentExecuted` watcher. |
170
+ | `migrateIcxToSoda` | full exec set | `'migrateIcxToSoda'` | |
171
+ | `revertMigrateSodaToIcx` | full exec set | `'revertMigrateSodaToIcx'` | |
172
+ | `migrateBaln` | full exec set | `'migrateBaln'` | |
173
+ | `create*Intent` | `VALIDATION_FAILED`, `INTENT_CREATION_FAILED`, `UNKNOWN` | matches | |
174
+ | `approve` | `VALIDATION_FAILED`, `APPROVE_FAILED`, `UNKNOWN` | matches | |
175
+ | `isAllowanceValid` | `VALIDATION_FAILED`, `ALLOWANCE_CHECK_FAILED`, `UNKNOWN` | n/a | |
176
+ | `getAvailableAmount` | `VALIDATION_FAILED`, `LOOKUP_FAILED`, `UNKNOWN` | n/a | `method: 'getAvailableAmount'` |
177
+
178
+ ## Cross-references
179
+
180
+ - v1 → v2 migration of this feature: [`../../migration/features/icx-bnusd-baln.md`](../../migration/features/icx-bnusd-baln.md).
181
+ - Architecture (relay layer's `phase: 'destinationExecution'` for bnUSD): [`../architecture.md`](../architecture.md) § 9.
@@ -0,0 +1,198 @@
1
+ # Money Market — `MoneyMarketService`
2
+
3
+ Cross-chain lending and borrowing. Supply, borrow, withdraw, repay across 19 spoke chains. Position state lives on the hub.
4
+
5
+ Access: `sodax.moneyMarket`. Service class: `MoneyMarketService`. Feature tag for errors: `'moneyMarket'`.
6
+
7
+ ## How it works
8
+
9
+ A user supplies on a spoke chain; the SDK relays the deposit to the hub, where the position is recorded against the user's hub wallet abstraction. Borrow can deliver funds back to the same chain (same-chain borrow) or to a different spoke chain (cross-chain borrow). Withdraw and repay reverse the flow.
10
+
11
+ aTokens (ERC4626 receipt tokens) live on the hub and represent the user's share of each reserve. Use `sodax.moneyMarket.getAToken(...)` to look them up.
12
+
13
+ ## Public methods
14
+
15
+ ```ts
16
+ // Mutations
17
+ sodax.moneyMarket.supply<K>(action): Promise<Result<TxHashPair, SodaxError>>;
18
+ sodax.moneyMarket.borrow<K>(action): Promise<Result<TxHashPair, SodaxError>>;
19
+ sodax.moneyMarket.withdraw<K>(action): Promise<Result<TxHashPair, SodaxError>>;
20
+ sodax.moneyMarket.repay<K>(action): Promise<Result<TxHashPair, SodaxError>>;
21
+
22
+ // Intent creators (raw-tx variant)
23
+ sodax.moneyMarket.createSupplyIntent<K, Raw>(...): Promise<Result<...>>;
24
+ sodax.moneyMarket.createBorrowIntent<K, Raw>(...): Promise<Result<...>>;
25
+ sodax.moneyMarket.createWithdrawIntent<K, Raw>(...): Promise<Result<...>>;
26
+ sodax.moneyMarket.createRepayIntent<K, Raw>(...): Promise<Result<...>>;
27
+
28
+ // Approve + allowance (action-discriminated)
29
+ sodax.moneyMarket.approve<K, Raw>(args): Promise<Result<TxReturnType<K, Raw>, SodaxError>>;
30
+ sodax.moneyMarket.isAllowanceValid<K>(args): Promise<Result<boolean, SodaxError>>;
31
+
32
+ // Estimation
33
+ sodax.moneyMarket.estimateGas<K>(params): Promise<Result<GetEstimateGasReturnType<K>, SodaxError>>;
34
+
35
+ // Reads (sync — config-derived, no I/O)
36
+ sodax.moneyMarket.getSupportedTokens(): GetMoneyMarketTokensApiResponse;
37
+ sodax.moneyMarket.getSupportedTokensByChainId(chainKey): readonly XToken[];
38
+ sodax.moneyMarket.getSupportedReserves(): readonly Address[];
39
+
40
+ // Hub-side calldata builders (Hex outputs; pre-flight inspection / custom orchestration)
41
+ sodax.moneyMarket.buildSupplyData(srcChainKey, fromToken, amount, toHubAddress): Hex;
42
+ sodax.moneyMarket.buildBorrowData(...): Hex;
43
+ sodax.moneyMarket.buildWithdrawData(...): Hex;
44
+ sodax.moneyMarket.buildRepayData(...): Hex;
45
+ ```
46
+
47
+ For per-position user reads (reserves data, user reserves data, formatted summaries, aToken balances, etc.) the entrypoint is `sodax.backendApi`, not `MoneyMarketService` — see `auxiliary-services.md` § "BackendApiService" for `getMoneyMarketPosition`, `getAllMoneyMarketAssets`, `getMoneyMarketAsset`, `getMoneyMarketAssetBorrowers`, `getMoneyMarketAssetSuppliers`, `getAllMoneyMarketBorrowers`.
48
+
49
+ ## Action params shape
50
+
51
+ `MoneyMarketParams<K>` is the shared base:
52
+
53
+ ```ts
54
+ type MoneyMarketParams<K extends SpokeChainKey> = {
55
+ srcChainKey: K;
56
+ srcAddress: GetAddressType<K>;
57
+ token: `0x${string}`; // hub asset address
58
+ amount: bigint;
59
+ };
60
+ ```
61
+
62
+ Per-action params:
63
+
64
+ ```ts
65
+ type MoneyMarketSupplyParams<K> = MoneyMarketParams<K> & { action: 'supply' };
66
+ type MoneyMarketWithdrawParams<K> = MoneyMarketParams<K> & { action: 'withdraw' };
67
+
68
+ type MoneyMarketBorrowParams<K> = MoneyMarketParams<K> & {
69
+ action: 'borrow';
70
+ dstChainKey?: SpokeChainKey; // delivery chain; defaults to srcChainKey
71
+ dstAddress?: string;
72
+ };
73
+ type MoneyMarketRepayParams<K> = MoneyMarketParams<K> & {
74
+ action: 'repay';
75
+ dstChainKey?: SpokeChainKey; // debt chain; defaults to srcChainKey
76
+ dstAddress?: string;
77
+ };
78
+ ```
79
+
80
+ ## Common call shapes
81
+
82
+ ### Supply (same-chain)
83
+
84
+ ```ts
85
+ const result = await sodax.moneyMarket.supply({
86
+ params: {
87
+ srcChainKey: ChainKeys.ARBITRUM_MAINNET,
88
+ srcAddress: '0x…',
89
+ token: USDC.address,
90
+ amount: parseUnits('100', 6),
91
+ action: 'supply',
92
+ },
93
+ raw: false,
94
+ walletProvider: evmWp,
95
+ });
96
+
97
+ if (!result.ok) return;
98
+ const { srcChainTxHash, dstChainTxHash } = result.value;
99
+ ```
100
+
101
+ ### Borrow (cross-chain)
102
+
103
+ Borrow on Arbitrum, deliver USDC to Stellar:
104
+
105
+ ```ts
106
+ await sodax.moneyMarket.borrow({
107
+ params: {
108
+ srcChainKey: ChainKeys.ARBITRUM_MAINNET,
109
+ srcAddress: '0x…',
110
+ token: USDC_ARBITRUM.address,
111
+ amount: parseUnits('50', 6),
112
+ action: 'borrow',
113
+ dstChainKey: ChainKeys.STELLAR_MAINNET,
114
+ dstAddress: 'G…',
115
+ },
116
+ raw: false,
117
+ walletProvider: evmWp,
118
+ });
119
+ ```
120
+
121
+ Same-chain borrow: omit `dstChainKey` and `dstAddress`.
122
+
123
+ ### Repay (cross-chain — pay from a different chain than the debt)
124
+
125
+ ```ts
126
+ await sodax.moneyMarket.repay({
127
+ params: {
128
+ srcChainKey: ChainKeys.BASE_MAINNET, // funds come from here
129
+ srcAddress: '0x…',
130
+ token: USDC_BASE.address,
131
+ amount: parseUnits('50', 6),
132
+ action: 'repay',
133
+ dstChainKey: ChainKeys.ARBITRUM_MAINNET, // debt lives here
134
+ dstAddress: '0x…',
135
+ },
136
+ raw: false,
137
+ walletProvider: baseWp, // wallet signs on the FROM chain (BASE)
138
+ });
139
+ ```
140
+
141
+ ### Approve / allowance check
142
+
143
+ ```ts
144
+ await sodax.moneyMarket.approve({
145
+ params: { srcChainKey, srcAddress, token, amount, action: 'supply' },
146
+ raw: false,
147
+ walletProvider: evmWp,
148
+ });
149
+
150
+ const allowed = await sodax.moneyMarket.isAllowanceValid({
151
+ params: { srcChainKey, srcAddress, token, amount, action: 'supply' },
152
+ });
153
+ ```
154
+
155
+ The `action` field routes to the right token under the hood — relevant for repay where the spent token may differ from the supplied token.
156
+
157
+ ## Return shapes
158
+
159
+ | Method | Success type |
160
+ |---|---|
161
+ | `supply`, `borrow`, `withdraw`, `repay` | `TxHashPair` = `{ srcChainTxHash, dstChainTxHash }` |
162
+ | `create*Intent` | `CreateIntentResult<K, Raw>` |
163
+ | `approve` | `TxReturnType<K, Raw>` |
164
+ | `isAllowanceValid` | `boolean` |
165
+ | `estimateGas` | `GetEstimateGasReturnType<K>` (chain-family-specific) |
166
+ | `getSupportedTokens` | `GetMoneyMarketTokensApiResponse` (record of chains → token arrays) |
167
+ | `getSupportedTokensByChainId` | `readonly XToken[]` |
168
+ | `getSupportedReserves` | `readonly Address[]` |
169
+ | `buildSupplyData` / `buildBorrowData` / `buildWithdrawData` / `buildRepayData` | `Hex` (calldata for hub-side calls) |
170
+
171
+ > Every cross-chain mutation across the SDK (bridge, staking, dex, migration, MM) returns `TxHashPair = { srcChainTxHash, dstChainTxHash }` — there is no array-form variant in v2.
172
+
173
+ ## Error codes
174
+
175
+ `feature: 'moneyMarket'`. Per-method narrow unions:
176
+
177
+ | Method | Codes | `error.context.action` |
178
+ |---|---|---|
179
+ | `supply` | full exec set | `'supply'` |
180
+ | `borrow` | full exec set | `'borrow'` |
181
+ | `withdraw` | full exec set | `'withdraw'` |
182
+ | `repay` | full exec set | `'repay'` |
183
+ | `create*Intent` | `VALIDATION_FAILED`, `INTENT_CREATION_FAILED`, `UNKNOWN` | matches action |
184
+ | `approve` | `VALIDATION_FAILED`, `APPROVE_FAILED`, `UNKNOWN` | matches action |
185
+ | `isAllowanceValid` | `VALIDATION_FAILED`, `ALLOWANCE_CHECK_FAILED`, `UNKNOWN` | matches action |
186
+ | Read methods | `VALIDATION_FAILED`, `LOOKUP_FAILED`, `UNKNOWN` | (use `error.context.method`) |
187
+
188
+ "Full exec set" = `VALIDATION_FAILED \| INTENT_CREATION_FAILED \| EXECUTION_FAILED \| TX_VERIFICATION_FAILED \| TX_SUBMIT_FAILED \| RELAY_TIMEOUT \| RELAY_FAILED \| UNKNOWN`.
189
+
190
+ ## RAY precision math
191
+
192
+ Aave's RAY precision (27 decimals) is used for interest calculations under the hood. Raw RAY values flow through `BackendApiService.getMoneyMarketAsset` / `getMoneyMarketPosition` (via `sodax.backendApi`); pre-formatted user-facing values come from the same backend service. Don't simplify the precision handling — porting Aave's `RayMath`/`PercentageMath` losslessly is a load-bearing requirement.
193
+
194
+ ## Cross-references
195
+
196
+ - v1 → v2 money market migration: [`../../migration/features/money-market.md`](../../migration/features/money-market.md).
197
+ - Architecture (hub-side wallet abstraction, ConfigService): [`../architecture.md`](../architecture.md) §§ 3, 4.
198
+ - Stellar destinations need a trustline: [`../chain-specifics.md`](../chain-specifics.md).