@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.
- 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 +342 -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 +126 -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 +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).
|