@sodax/sdk 2.0.0-rc.2 → 2.0.0-rc.4
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 +8 -60
- package/dist/index.cjs +28 -39
- package/dist/index.d.cts +21 -108
- package/dist/index.d.ts +21 -108
- package/dist/index.mjs +34 -43
- package/package.json +22 -21
- package/ai-exported/AGENTS.md +0 -99
- package/ai-exported/integration/README.md +0 -41
- package/ai-exported/integration/ai-rules.md +0 -75
- package/ai-exported/integration/architecture.md +0 -519
- package/ai-exported/integration/chain-specifics.md +0 -189
- package/ai-exported/integration/features/README.md +0 -19
- package/ai-exported/integration/features/auxiliary-services.md +0 -189
- package/ai-exported/integration/features/bridge.md +0 -136
- package/ai-exported/integration/features/dex.md +0 -182
- package/ai-exported/integration/features/icx-bnusd-baln.md +0 -181
- package/ai-exported/integration/features/money-market.md +0 -198
- package/ai-exported/integration/features/staking.md +0 -166
- package/ai-exported/integration/features/swap.md +0 -207
- package/ai-exported/integration/quickstart.md +0 -213
- package/ai-exported/integration/recipes/README.md +0 -21
- package/ai-exported/integration/recipes/backend-server-init.md +0 -69
- package/ai-exported/integration/recipes/chain-key-narrowing.md +0 -65
- package/ai-exported/integration/recipes/gas-estimation.md +0 -33
- package/ai-exported/integration/recipes/initialize-sodax.md +0 -53
- package/ai-exported/integration/recipes/raw-tx-flow.md +0 -71
- package/ai-exported/integration/recipes/result-and-errors.md +0 -104
- package/ai-exported/integration/recipes/signed-tx-flow.md +0 -46
- package/ai-exported/integration/recipes/testing.md +0 -101
- package/ai-exported/integration/reference/README.md +0 -18
- package/ai-exported/integration/reference/chain-keys.md +0 -67
- package/ai-exported/integration/reference/error-codes.md +0 -165
- package/ai-exported/integration/reference/glossary.md +0 -32
- package/ai-exported/integration/reference/public-api.md +0 -138
- package/ai-exported/integration/reference/wallet-providers.md +0 -62
- package/ai-exported/migration/README.md +0 -58
- package/ai-exported/migration/ai-rules.md +0 -80
- package/ai-exported/migration/breaking-changes/architecture.md +0 -342
- package/ai-exported/migration/breaking-changes/result-and-errors.md +0 -363
- package/ai-exported/migration/breaking-changes/type-system.md +0 -321
- package/ai-exported/migration/checklist.md +0 -61
- package/ai-exported/migration/features/README.md +0 -35
- package/ai-exported/migration/features/auxiliary-services.md +0 -156
- package/ai-exported/migration/features/bridge.md +0 -125
- package/ai-exported/migration/features/dex.md +0 -143
- package/ai-exported/migration/features/icx-bnusd-baln.md +0 -151
- package/ai-exported/migration/features/money-market.md +0 -214
- package/ai-exported/migration/features/staking.md +0 -138
- package/ai-exported/migration/features/swap.md +0 -198
- package/ai-exported/migration/recipes.md +0 -288
- package/ai-exported/migration/reference/README.md +0 -18
- package/ai-exported/migration/reference/deleted-exports.md +0 -126
- package/ai-exported/migration/reference/error-code-crosswalk.md +0 -104
- package/ai-exported/migration/reference/return-shapes.md +0 -49
- package/ai-exported/migration/reference/sodax-config.md +0 -52
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs.map +0 -1
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
# Staking — `StakingService`
|
|
2
|
-
|
|
3
|
-
SODA token staking via an ERC4626 vault (xSoda). Stake, unstake (with penalty curve), instant unstake (slippage), claim, cancel-unstake. All operations are cross-chain — staking writes happen on the hub even when the user is on a spoke chain.
|
|
4
|
-
|
|
5
|
-
Access: `sodax.staking`. Service class: `StakingService`. Feature tag for errors: `'staking'`.
|
|
6
|
-
|
|
7
|
-
## How it works
|
|
8
|
-
|
|
9
|
-
- **SODA** (the staked asset) → **xSoda** (ERC4626 vault shares, proportional to current exchange rate).
|
|
10
|
-
- **Unstake** has a configurable waiting period with linear penalty (max 1–100%).
|
|
11
|
-
- **Instant unstake** bypasses the waiting period but pays slippage (via `StakingRouter`).
|
|
12
|
-
- **Claim** redeems SODA after the unstaking period expires.
|
|
13
|
-
- **Cancel unstake** restores xSoda from a pending unstake request before claim.
|
|
14
|
-
|
|
15
|
-
## Public methods
|
|
16
|
-
|
|
17
|
-
```ts
|
|
18
|
-
sodax.staking.stake<K>(action: StakeAction<K, false>): Promise<Result<TxHashPair, SodaxError>>;
|
|
19
|
-
sodax.staking.unstake<K>(action: UnstakeAction<K, false>): Promise<Result<TxHashPair, SodaxError>>;
|
|
20
|
-
sodax.staking.instantUnstake<K>(action: InstantUnstakeAction<K, false>): Promise<Result<TxHashPair, SodaxError>>;
|
|
21
|
-
sodax.staking.claim<K>(action: ClaimAction<K, false>): Promise<Result<TxHashPair, SodaxError>>;
|
|
22
|
-
sodax.staking.cancelUnstake<K>(action: CancelUnstakeAction<K, false>): Promise<Result<TxHashPair, SodaxError>>;
|
|
23
|
-
|
|
24
|
-
sodax.staking.createStakeIntent<K, Raw>(...): Promise<Result<...>>;
|
|
25
|
-
// + the 4 other createXxxIntent methods
|
|
26
|
-
|
|
27
|
-
sodax.staking.approve<K, Raw>(args): Promise<Result<TxReturnType<K, Raw>, SodaxError>>;
|
|
28
|
-
sodax.staking.isAllowanceValid<K, Raw>(args): Promise<Result<boolean, SodaxError>>;
|
|
29
|
-
|
|
30
|
-
// Reads (hub-only — no chain context needed):
|
|
31
|
-
sodax.staking.getStakingConfig(): Promise<Result<StakingConfig, SodaxError>>;
|
|
32
|
-
sodax.staking.getStakeRatio(amount): Promise<Result<[bigint, bigint], SodaxError>>;
|
|
33
|
-
// value: [xSodaAmount, previewDepositAmount]
|
|
34
|
-
sodax.staking.getInstantUnstakeRatio(amount): Promise<Result<bigint, SodaxError>>;
|
|
35
|
-
sodax.staking.getConvertedAssets(amount): Promise<Result<bigint, SodaxError>>;
|
|
36
|
-
|
|
37
|
-
// Reads (cross-chain — derive hub wallet from src chain):
|
|
38
|
-
sodax.staking.getStakingInfoFromSpoke(srcAddress, srcChainKey): Promise<Result<StakingInfo, SodaxError>>;
|
|
39
|
-
sodax.staking.getUnstakingInfo(srcAddress, srcChainKey): Promise<Result<UnstakingInfo, SodaxError>>;
|
|
40
|
-
// value: { userUnstakeSodaRequests: UserUnstakeInfo[]; totalUnstaking: bigint }
|
|
41
|
-
sodax.staking.getUnstakingInfoWithPenalty(srcAddress, srcChainKey): Promise<Result<UnstakingInfo & { requestsWithPenalty: UnstakeRequestWithPenalty[] }, SodaxError>>;
|
|
42
|
-
// each request adds penalty, penaltyPercentage, claimableAmount
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Action params shape
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
type StakeParams<K extends SpokeChainKey> = {
|
|
49
|
-
srcChainKey: K;
|
|
50
|
-
srcAddress: GetAddressType<K>;
|
|
51
|
-
amount: bigint;
|
|
52
|
-
minReceive: bigint; // min xSoda after slippage; gate against bad rates
|
|
53
|
-
action: 'stake';
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
type UnstakeParams<K> = { srcChainKey: K; srcAddress; amount: bigint; action: 'unstake' };
|
|
57
|
-
type InstantUnstakeParams<K> = { srcChainKey: K; srcAddress; amount: bigint; minAmount: bigint; action: 'instantUnstake' };
|
|
58
|
-
type ClaimParams<K> = { srcChainKey: K; srcAddress; requestId: bigint; amount: bigint; action: 'claim' };
|
|
59
|
-
type CancelUnstakeParams<K> = { srcChainKey: K; srcAddress; requestId: bigint; action: 'cancelUnstake' };
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
`StakingParamsUnion<K, Raw>` is the union of all 5; consumed by `staking.approve` and `staking.isAllowanceValid` (action-discriminated).
|
|
63
|
-
|
|
64
|
-
## Common call shapes
|
|
65
|
-
|
|
66
|
-
### Stake
|
|
67
|
-
|
|
68
|
-
```ts
|
|
69
|
-
const result = await sodax.staking.stake({
|
|
70
|
-
params: {
|
|
71
|
-
srcChainKey: ChainKeys.ARBITRUM_MAINNET,
|
|
72
|
-
srcAddress: '0x…',
|
|
73
|
-
amount: parseUnits('100', 18), // 100 SODA
|
|
74
|
-
minReceive: parseUnits('99', 18), // expect ~1% slippage tolerance
|
|
75
|
-
action: 'stake',
|
|
76
|
-
},
|
|
77
|
-
raw: false,
|
|
78
|
-
walletProvider: evmWp,
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
if (!result.ok) return;
|
|
82
|
-
const { srcChainTxHash, dstChainTxHash } = result.value;
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Unstake (with penalty curve)
|
|
86
|
-
|
|
87
|
-
```ts
|
|
88
|
-
await sodax.staking.unstake({
|
|
89
|
-
params: { srcChainKey, srcAddress, amount: xSodaAmount, action: 'unstake' },
|
|
90
|
-
raw: false,
|
|
91
|
-
walletProvider,
|
|
92
|
-
});
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Creates a pending unstake request. After the staking period expires, call `claim`. Use `getUnstakingInfoWithPenalty` to see the current penalty for early withdrawal.
|
|
96
|
-
|
|
97
|
-
### Instant unstake
|
|
98
|
-
|
|
99
|
-
```ts
|
|
100
|
-
await sodax.staking.instantUnstake({
|
|
101
|
-
params: {
|
|
102
|
-
srcChainKey, srcAddress,
|
|
103
|
-
amount: xSodaAmount,
|
|
104
|
-
minAmount: minSodaAfterSlippage,
|
|
105
|
-
action: 'instantUnstake',
|
|
106
|
-
},
|
|
107
|
-
raw: false,
|
|
108
|
-
walletProvider,
|
|
109
|
-
});
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
Bypasses the waiting period; pays slippage via `StakingRouter`.
|
|
113
|
-
|
|
114
|
-
### Approve / allowance — action-discriminated
|
|
115
|
-
|
|
116
|
-
The `approve` method routes by `params.action` to approve the right token (SODA for `stake`, xSoda for `unstake` and `instantUnstake`):
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
await sodax.staking.approve({
|
|
120
|
-
params: { srcChainKey, srcAddress, amount, action: 'stake' /* or 'unstake' or 'instantUnstake' */ },
|
|
121
|
-
raw: false,
|
|
122
|
-
walletProvider,
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
const allowed = await sodax.staking.isAllowanceValid({
|
|
126
|
-
params: { srcChainKey, srcAddress, amount, action: 'stake' },
|
|
127
|
-
raw: true, // read-only
|
|
128
|
-
});
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## Return shapes
|
|
132
|
-
|
|
133
|
-
| Method | Success type |
|
|
134
|
-
|---|---|
|
|
135
|
-
| `stake`, `unstake`, `instantUnstake`, `claim`, `cancelUnstake` | `TxHashPair` |
|
|
136
|
-
| `create*Intent` | `CreateIntentResult<K, Raw>` |
|
|
137
|
-
| `approve` | `TxReturnType<K, Raw>` |
|
|
138
|
-
| `isAllowanceValid` | `boolean` |
|
|
139
|
-
| `getStakingConfig` | `{ unstakingPeriod, maxPenalty, minPenalty, /* … */ }` |
|
|
140
|
-
| `getStakeRatio` | `[xSodaAmount: bigint, previewDepositAmount: bigint]` (estimated xSoda shares + vault's `previewDeposit` preview) |
|
|
141
|
-
| `getInstantUnstakeRatio` | `bigint` |
|
|
142
|
-
| `getConvertedAssets` | `bigint` (SODA per xSoda) |
|
|
143
|
-
| `getStakingInfoFromSpoke` | `StakingInfo` (xSoda balance, accrued, etc.) |
|
|
144
|
-
| `getUnstakingInfo` | `UnstakingInfo` (object; carries `userUnstakeSodaRequests` array + aggregate amount) |
|
|
145
|
-
| `getUnstakingInfoWithPenalty` | `UnstakingInfo & { requestsWithPenalty: UnstakeRequestWithPenalty[] }` (each entry adds `penalty`, `penaltyPercentage`, `claimableAmount`) |
|
|
146
|
-
|
|
147
|
-
> All 5 mutation methods return `TxHashPair = { srcChainTxHash, dstChainTxHash }` because the SDK relays spoke→hub internally. When the user is already on the hub, both fields hold the same hash.
|
|
148
|
-
|
|
149
|
-
## Error codes
|
|
150
|
-
|
|
151
|
-
`feature: 'staking'`. Per-method narrow unions:
|
|
152
|
-
|
|
153
|
-
| Method | Codes | Action |
|
|
154
|
-
|---|---|---|
|
|
155
|
-
| `stake` | full exec set incl. `TX_VERIFICATION_FAILED` (only stake calls verifyTxHash) | `'stake'` |
|
|
156
|
-
| `unstake`, `instantUnstake`, `claim`, `cancelUnstake` | full exec set minus `TX_VERIFICATION_FAILED` | matches action |
|
|
157
|
-
| `approve` | `VALIDATION_FAILED`, `APPROVE_FAILED`, `UNKNOWN` | matches action |
|
|
158
|
-
| `isAllowanceValid` | `VALIDATION_FAILED`, `ALLOWANCE_CHECK_FAILED`, `UNKNOWN` | matches action |
|
|
159
|
-
| Read methods (8 of them) | `VALIDATION_FAILED`, `LOOKUP_FAILED`, `UNKNOWN` | (use `error.context.method`) |
|
|
160
|
-
|
|
161
|
-
`StakingLogic` (a static utility class for contract encoding and on-chain reads) keeps its throw-on-error contract — wrapping happens only in `StakingService` public methods.
|
|
162
|
-
|
|
163
|
-
## Cross-references
|
|
164
|
-
|
|
165
|
-
- v1 → v2 staking migration: [`../../migration/features/staking.md`](../../migration/features/staking.md).
|
|
166
|
-
- ERC4626 vault concept (xSoda): see SODAX docs site or `@sodax/sdk` source.
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
# Swap — `SwapService`
|
|
2
|
-
|
|
3
|
-
Intent-based swaps via a solver. Cross-chain by default.
|
|
4
|
-
|
|
5
|
-
Access: `sodax.swaps`. Service class: `SwapService`. Feature tag for errors: `'swap'`.
|
|
6
|
-
|
|
7
|
-
## How it works
|
|
8
|
-
|
|
9
|
-
1. **Build an intent** — `createIntent` signs a spoke transaction encoding the swap declaration.
|
|
10
|
-
2. **Relay to hub** — handled internally; the spoke tx propagates to Sonic.
|
|
11
|
-
3. **Solver fulfillment** — an off-chain solver picks up the intent and fills it on the destination chain.
|
|
12
|
-
4. **Post-execution settlement** — `postExecution` finalizes the user's side once the solver completes.
|
|
13
|
-
|
|
14
|
-
Two execution paths:
|
|
15
|
-
|
|
16
|
-
- **`swap`** — full flow in one call. Wraps `createIntent` + relay + `postExecution`. Returns `SwapResponse` on success.
|
|
17
|
-
- **`createIntent` + backend submit** — break it apart for custom relay handling. `createIntent` returns `{ tx, intent, relayData }`; submit `relayData.payload` to the backend swap-tx endpoint via `BackendApiService.submitSwapTx`.
|
|
18
|
-
|
|
19
|
-
## Public methods
|
|
20
|
-
|
|
21
|
-
```ts
|
|
22
|
-
sodax.swaps.swap<K extends SpokeChainKey>(action: SwapActionParams<K, false>): Promise<Result<SwapResponse, SodaxError>>;
|
|
23
|
-
|
|
24
|
-
sodax.swaps.createIntent<K extends SpokeChainKey, Raw extends boolean>(
|
|
25
|
-
action: SwapActionParams<K, Raw>,
|
|
26
|
-
): Promise<Result<CreateIntentResult<K, Raw>, SodaxError>>;
|
|
27
|
-
|
|
28
|
-
sodax.swaps.postExecution(
|
|
29
|
-
args: { intent, relayData },
|
|
30
|
-
): Promise<Result<SwapResponse, SodaxError>>;
|
|
31
|
-
|
|
32
|
-
sodax.swaps.createLimitOrder<K, Raw>(
|
|
33
|
-
action: LimitOrderActionParams<K, Raw>,
|
|
34
|
-
): Promise<Result<CreateIntentResult<K, Raw>, SodaxError>>;
|
|
35
|
-
|
|
36
|
-
sodax.swaps.createLimitOrderIntent<K, Raw>(/* same as createIntent shape with limit-order params */): /* same return */;
|
|
37
|
-
|
|
38
|
-
sodax.swaps.cancelIntent<K, Raw>(/* … */): Promise<Result<TxReturnType<K, Raw>, SodaxError>>;
|
|
39
|
-
sodax.swaps.cancelLimitOrder<K, Raw>(/* … */): Promise<Result<TxReturnType<K, Raw>, SodaxError>>;
|
|
40
|
-
|
|
41
|
-
sodax.swaps.approve<K, Raw>(/* … */): Promise<Result<TxReturnType<K, Raw>, SodaxError>>;
|
|
42
|
-
sodax.swaps.isAllowanceValid<K, Raw>(/* … */): Promise<Result<boolean, SodaxError>>;
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Action params shape
|
|
46
|
-
|
|
47
|
-
Generic `K extends SpokeChainKey` carries the literal source chain key. `WalletProviderSlot<K, Raw>` is intersected:
|
|
48
|
-
|
|
49
|
-
```ts
|
|
50
|
-
type SwapActionParams<K extends SpokeChainKey, Raw extends boolean> = {
|
|
51
|
-
params: CreateIntentParams<K>;
|
|
52
|
-
skipSimulation?: boolean;
|
|
53
|
-
timeout?: number;
|
|
54
|
-
fee?: PartnerFee;
|
|
55
|
-
} & WalletProviderSlot<K, Raw>;
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
`CreateIntentParams<K>`:
|
|
59
|
-
|
|
60
|
-
```ts
|
|
61
|
-
type CreateIntentParams<K extends SpokeChainKey> = {
|
|
62
|
-
srcChainKey: K;
|
|
63
|
-
dstChainKey: SpokeChainKey;
|
|
64
|
-
srcAddress: GetAddressType<K>;
|
|
65
|
-
dstAddress: string; // chain-specific format on the destination side
|
|
66
|
-
inputToken: XToken; // must have chainKey === srcChainKey
|
|
67
|
-
outputToken: XToken; // must have chainKey === dstChainKey
|
|
68
|
-
inputAmount: bigint;
|
|
69
|
-
minOutputAmount: bigint;
|
|
70
|
-
deadline: bigint; // unix seconds
|
|
71
|
-
allowPartialFill: boolean;
|
|
72
|
-
solver: `0x${string}`; // solver address; '0x0…0' for default
|
|
73
|
-
data: `0x${string}`; // arbitrary calldata; '0x' for default
|
|
74
|
-
};
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
`CreateLimitOrderParams<K>` is `Omit<CreateIntentParams<K>, 'deadline'>` (limit orders have a different expiry mechanism).
|
|
78
|
-
|
|
79
|
-
## Common call shapes
|
|
80
|
-
|
|
81
|
-
### Signed swap (full flow)
|
|
82
|
-
|
|
83
|
-
```ts
|
|
84
|
-
const result = await sodax.swaps.swap({
|
|
85
|
-
params: {
|
|
86
|
-
srcChainKey: ChainKeys.ARBITRUM_MAINNET,
|
|
87
|
-
dstChainKey: ChainKeys.STELLAR_MAINNET,
|
|
88
|
-
srcAddress: '0x…',
|
|
89
|
-
dstAddress: 'G…',
|
|
90
|
-
inputToken: USDC_ARBITRUM, // XToken with chainKey === ARBITRUM_MAINNET
|
|
91
|
-
outputToken: XLM, // XToken with chainKey === STELLAR_MAINNET
|
|
92
|
-
inputAmount: 1_000_000n, // 1 USDC (6 decimals)
|
|
93
|
-
minOutputAmount: 500_0000000n, // 50 XLM (7 decimals)
|
|
94
|
-
deadline: BigInt(Math.floor(Date.now() / 1000) + 300),
|
|
95
|
-
allowPartialFill: false,
|
|
96
|
-
solver: '0x0000000000000000000000000000000000000000',
|
|
97
|
-
data: '0x',
|
|
98
|
-
},
|
|
99
|
-
raw: false,
|
|
100
|
-
walletProvider: evmWp,
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
if (!result.ok) return;
|
|
104
|
-
const { solverExecutionResponse, intent, intentDeliveryInfo } = result.value;
|
|
105
|
-
// SwapResponse: { solverExecutionResponse, intent, intentDeliveryInfo }
|
|
106
|
-
// Use `intentDeliveryInfo` for spoke / hub tx hashes; `solverExecutionResponse` for solver-side outcome.
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Create intent only (custom relay)
|
|
110
|
-
|
|
111
|
-
```ts
|
|
112
|
-
const result = await sodax.swaps.createIntent({
|
|
113
|
-
params: { /* … */ },
|
|
114
|
-
raw: false,
|
|
115
|
-
walletProvider: evmWp,
|
|
116
|
-
});
|
|
117
|
-
if (!result.ok) return;
|
|
118
|
-
|
|
119
|
-
const { tx: spokeTxHash, intent, relayData } = result.value;
|
|
120
|
-
// tx is the spoke tx hash (TxReturnType<K, false>) for raw: false
|
|
121
|
-
// relayData is { payload: string }; submit relayData.payload to your backend
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Backend submit-tx flow
|
|
125
|
-
|
|
126
|
-
```ts
|
|
127
|
-
const submitResult = await sodax.backendApi.submitSwapTx({
|
|
128
|
-
txHash: spokeTxHash as string,
|
|
129
|
-
srcChainKey: ChainKeys.ARBITRUM_MAINNET,
|
|
130
|
-
walletAddress: '0x…',
|
|
131
|
-
intent: /* SwapIntentData built from CreateIntentResult.value.intent */,
|
|
132
|
-
relayData: relayData.payload, // string (not the object)
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
if (!submitResult.ok) {
|
|
136
|
-
// submitResult.error.code: 'EXTERNAL_API_ERROR' with context.api: 'backend'
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### Raw-tx flow
|
|
142
|
-
|
|
143
|
-
```ts
|
|
144
|
-
const result = await sodax.swaps.createIntent({
|
|
145
|
-
params: { /* … */ },
|
|
146
|
-
raw: true,
|
|
147
|
-
// walletProvider is forbidden here
|
|
148
|
-
});
|
|
149
|
-
if (!result.ok) return;
|
|
150
|
-
const { tx, intent, relayData } = result.value;
|
|
151
|
-
// tx: chain-specific raw-tx payload (EvmRawTransaction, SolanaRawTransaction, …)
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Cancel intent
|
|
155
|
-
|
|
156
|
-
```ts
|
|
157
|
-
await sodax.swaps.cancelIntent({
|
|
158
|
-
params: { srcChainKey, intent /* the full Intent struct */ },
|
|
159
|
-
raw: false,
|
|
160
|
-
walletProvider: evmWp,
|
|
161
|
-
});
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
## Return shapes
|
|
165
|
-
|
|
166
|
-
| Method | Success type |
|
|
167
|
-
|---|---|
|
|
168
|
-
| `swap` | `SwapResponse` = `{ solverExecutionResponse, intent, intentDeliveryInfo }` |
|
|
169
|
-
| `createIntent` | `CreateIntentResult<K, Raw>` = `{ tx: TxReturnType<K, Raw>, intent: Intent & FeeAmount, relayData: RelayExtraData }` |
|
|
170
|
-
| `postExecution` | `SwapResponse` |
|
|
171
|
-
| `createLimitOrder` / `createLimitOrderIntent` | Same as `createIntent` |
|
|
172
|
-
| `cancelIntent` / `cancelLimitOrder` | `TxReturnType<K, Raw>` |
|
|
173
|
-
| `approve` | `TxReturnType<K, Raw>` |
|
|
174
|
-
| `isAllowanceValid` | `boolean` |
|
|
175
|
-
|
|
176
|
-
`RelayExtraData`:
|
|
177
|
-
|
|
178
|
-
```ts
|
|
179
|
-
type RelayExtraData = {
|
|
180
|
-
payload: string; // pass this string to backend submit-tx as `relayData`
|
|
181
|
-
};
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## Error codes
|
|
185
|
-
|
|
186
|
-
`feature: 'swap'`. Per-method narrow unions:
|
|
187
|
-
|
|
188
|
-
| Method | Codes |
|
|
189
|
-
|---|---|
|
|
190
|
-
| `createIntent`, `createLimitOrderIntent` | `VALIDATION_FAILED`, `INTENT_CREATION_FAILED`, `UNKNOWN` |
|
|
191
|
-
| `swap`, `createLimitOrder` | `VALIDATION_FAILED`, `INTENT_CREATION_FAILED`, `EXECUTION_FAILED`, `TX_VERIFICATION_FAILED`, `TX_SUBMIT_FAILED`, `RELAY_TIMEOUT`, `RELAY_FAILED`, `EXTERNAL_API_ERROR`, `UNKNOWN` |
|
|
192
|
-
| `postExecution` | `EXECUTION_FAILED` (with `phase: 'postExecution'`), `EXTERNAL_API_ERROR` (with `api: 'solver'`), `UNKNOWN` |
|
|
193
|
-
| `cancelIntent`, `cancelLimitOrder` | `VALIDATION_FAILED`, `EXECUTION_FAILED`, `UNKNOWN` |
|
|
194
|
-
| `approve` | `VALIDATION_FAILED`, `APPROVE_FAILED`, `UNKNOWN` |
|
|
195
|
-
| `isAllowanceValid` | `VALIDATION_FAILED`, `ALLOWANCE_CHECK_FAILED`, `UNKNOWN` |
|
|
196
|
-
|
|
197
|
-
Solver-specific context on `EXTERNAL_API_ERROR`:
|
|
198
|
-
|
|
199
|
-
- `error.context.api === 'solver'`
|
|
200
|
-
- `error.context.solverCode` — the solver's own error code (e.g. `'INSUFFICIENT_LIQUIDITY'`)
|
|
201
|
-
- `error.context.solverDetail` — the solver's human-readable message
|
|
202
|
-
|
|
203
|
-
## Cross-references
|
|
204
|
-
|
|
205
|
-
- v1 → v2 swap migration: [`../../migration/features/swap.md`](../../migration/features/swap.md).
|
|
206
|
-
- Error model: [`../architecture.md`](../architecture.md) § 8 and [`../reference/`](../reference/) § 3.
|
|
207
|
-
- Stellar destinations require a trustline first: [`../chain-specifics.md`](../chain-specifics.md) § "Stellar trustline".
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
# Quickstart — `@sodax/sdk` v2
|
|
2
|
-
|
|
3
|
-
Get a `Sodax` instance running in your project. This guide is **`@sodax/sdk`-only**: no other SODAX packages are imported. Where the SDK needs an `I*WalletProvider` instance, examples use a TypeScript `declare` placeholder so the surface stays Core-SDK-clean.
|
|
4
|
-
|
|
5
|
-
## Section index
|
|
6
|
-
|
|
7
|
-
1. [Installation](#1-installation)
|
|
8
|
-
2. [TypeScript](#2-typescript)
|
|
9
|
-
3. [The wallet-provider contract](#3-the-wallet-provider-contract)
|
|
10
|
-
4. [Where to get wallet-provider implementations](#4-where-to-get-wallet-provider-implementations)
|
|
11
|
-
5. [Construct + initialize](#5-construct--initialize)
|
|
12
|
-
6. [Reads without a wallet](#6-reads-without-a-wallet)
|
|
13
|
-
7. [Build raw transactions (no wallet)](#7-build-raw-transactions-no-wallet)
|
|
14
|
-
8. [Calling methods that sign](#8-calling-methods-that-sign)
|
|
15
|
-
9. [First-time troubleshooting](#9-first-time-troubleshooting)
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## 1. Installation
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
pnpm add @sodax/sdk
|
|
23
|
-
# or
|
|
24
|
-
npm install @sodax/sdk
|
|
25
|
-
# or
|
|
26
|
-
yarn add @sodax/sdk
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
**Don't add `@sodax/types` separately.** `@sodax/sdk` re-exports the entire types surface from its barrel. Adding `@sodax/types` as a direct dependency invites version skew on the next minor bump.
|
|
30
|
-
|
|
31
|
-
## 2. TypeScript
|
|
32
|
-
|
|
33
|
-
Targets Node 18+ and modern browsers. The package ships dual ESM (`.mjs`) + CJS (`.cjs`) + DTS, with `"type": "module"`. No additional TypeScript config needed — the package's `exports` field handles resolution for both `tsc` and `bundler` `moduleResolution` modes.
|
|
34
|
-
|
|
35
|
-
If you're on `moduleResolution: 'node'` (legacy), upgrade to `'bundler'` or `'node16'` / `'nodenext'` — `'node'` doesn't read the `exports` field and will fall back to `main` / `module` (which still work, but you may see resolution warnings).
|
|
36
|
-
|
|
37
|
-
## 3. The wallet-provider contract
|
|
38
|
-
|
|
39
|
-
Methods that sign and broadcast take a `walletProvider` parameter typed as the chain-specific `I*WalletProvider` interface (`IEvmWalletProvider`, `ISolanaWalletProvider`, `ISuiWalletProvider`, `IStellarWalletProvider`, `IIconWalletProvider`, `IInjectiveWalletProvider`, `IStacksWalletProvider`, `INearWalletProvider`, `IBitcoinWalletProvider`). All nine interfaces are exported from `@sodax/sdk`.
|
|
40
|
-
|
|
41
|
-
`@sodax/sdk` does **not** ship implementations of these interfaces. Read methods (`sodax.config.*`, `sodax.bridge.getBridgeableAmount`, `sodax.staking.getStakingConfig`, etc.) and `raw: true` flows do not require a `walletProvider`.
|
|
42
|
-
|
|
43
|
-
## 4. Where to get wallet-provider implementations
|
|
44
|
-
|
|
45
|
-
Two options:
|
|
46
|
-
|
|
47
|
-
1. **Implement the interface yourself.** Each `I*WalletProvider` is a small set of methods (`getWalletAddress`, plus chain-specific signing / broadcasting). Wrap whatever wallet abstraction your app already owns (`viem`'s `WalletClient` for EVM, `@solana/web3.js` keypairs for Solana, `@stellar/stellar-sdk` for Stellar, etc.) in an object literal that satisfies the interface.
|
|
48
|
-
2. **Use `@sodax/wallet-sdk-core`** — a separate SODAX package (not part of `@sodax/sdk`, not a transitive dependency — install it separately) that ships ready-made `I*WalletProvider` implementations for all 9 chain families with both private-key (Node / scripts) and browser-extension (dApp) modes. Refer to that package's own documentation for usage.
|
|
49
|
-
|
|
50
|
-
Examples in this guide use TypeScript `declare const` placeholders so the surface stays Core-SDK-only — substitute your own object regardless of which option you chose.
|
|
51
|
-
|
|
52
|
-
## 5. Construct + initialize
|
|
53
|
-
|
|
54
|
-
```ts
|
|
55
|
-
import { Sodax } from '@sodax/sdk';
|
|
56
|
-
|
|
57
|
-
const sodax = new Sodax();
|
|
58
|
-
await sodax.config.initialize(); // load fresh config from backend; falls back to packaged defaults
|
|
59
|
-
|
|
60
|
-
// All feature services are wired and ready:
|
|
61
|
-
// sodax.swaps, sodax.moneyMarket, sodax.bridge, sodax.staking,
|
|
62
|
-
// sodax.dex, sodax.migration, sodax.partners, sodax.recovery,
|
|
63
|
-
// sodax.config, sodax.backendApi, sodax.hubProvider, sodax.spoke
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
`new Sodax()` accepts an optional `DeepPartial<SodaxConfig>` for custom RPC endpoints, solver / backend URLs, etc. — see [`recipes/`](recipes/) § "Initialize Sodax". `initialize()` is idempotent.
|
|
67
|
-
|
|
68
|
-
## 6. Reads without a wallet
|
|
69
|
-
|
|
70
|
-
Many SDK calls are pure reads — no wallet provider, no signing. They're the cheapest path to verifying an integration:
|
|
71
|
-
|
|
72
|
-
```ts
|
|
73
|
-
import { Sodax, ChainKeys } from '@sodax/sdk';
|
|
74
|
-
|
|
75
|
-
const sodax = new Sodax();
|
|
76
|
-
await sodax.config.initialize();
|
|
77
|
-
|
|
78
|
-
// Config / token lookups
|
|
79
|
-
const usdc = sodax.config.findSupportedTokenBySymbol(ChainKeys.ARBITRUM_MAINNET, 'USDC');
|
|
80
|
-
const isValid = sodax.config.isValidSpokeChainKey(ChainKeys.ARBITRUM_MAINNET);
|
|
81
|
-
|
|
82
|
-
// Money market
|
|
83
|
-
const supplyTokens = sodax.moneyMarket.getSupportedTokensByChainId(ChainKeys.ARBITRUM_MAINNET);
|
|
84
|
-
|
|
85
|
-
// Bridge
|
|
86
|
-
const limit = await sodax.bridge.getBridgeableAmount(USDC_ARBITRUM, USDC_STELLAR);
|
|
87
|
-
// limit.value: BridgeLimit = { amount, decimals, type }
|
|
88
|
-
|
|
89
|
-
// Staking (hub-only reads — no chain context needed)
|
|
90
|
-
const stakingConfig = await sodax.staking.getStakingConfig();
|
|
91
|
-
|
|
92
|
-
// DEX
|
|
93
|
-
const pools = sodax.dex.clService.getPools(); // synchronous in v2
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## 7. Build raw transactions (no wallet)
|
|
97
|
-
|
|
98
|
-
For sign-elsewhere flows (gnosis safe, hardware wallet, custom multi-sig), use `raw: true`. The SDK builds the unsigned payload; your application signs and broadcasts:
|
|
99
|
-
|
|
100
|
-
```ts
|
|
101
|
-
import { Sodax, ChainKeys } from '@sodax/sdk';
|
|
102
|
-
|
|
103
|
-
const sodax = new Sodax();
|
|
104
|
-
await sodax.config.initialize();
|
|
105
|
-
|
|
106
|
-
const result = await sodax.swaps.createIntent({
|
|
107
|
-
params: {
|
|
108
|
-
srcChainKey: ChainKeys.ARBITRUM_MAINNET,
|
|
109
|
-
dstChainKey: ChainKeys.STELLAR_MAINNET,
|
|
110
|
-
/* … rest of intent params */
|
|
111
|
-
},
|
|
112
|
-
raw: true,
|
|
113
|
-
// walletProvider is FORBIDDEN when raw: true — TypeScript rejects it.
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
if (!result.ok) {
|
|
117
|
-
console.error(result.error.toJSON());
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
const { tx, intent, relayData } = result.value;
|
|
121
|
-
// tx: chain-specific raw-tx payload (EvmRawTransaction, SolanaRawTransaction, …)
|
|
122
|
-
// Sign and broadcast `tx` with whatever signer your application owns.
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
## 8. Calling methods that sign
|
|
126
|
-
|
|
127
|
-
For signed flows, supply an `I*WalletProvider`. The example uses a TypeScript `declare` placeholder — at runtime, substitute an object your application owns (one you implemented to satisfy the interface, or one constructed via `@sodax/wallet-sdk-core`).
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
|
-
import { Sodax, ChainKeys, type IEvmWalletProvider } from '@sodax/sdk';
|
|
131
|
-
|
|
132
|
-
declare const evmWallet: IEvmWalletProvider;
|
|
133
|
-
// ↑ At runtime, replace with your application's wallet-provider object.
|
|
134
|
-
// Any object that satisfies IEvmWalletProvider works.
|
|
135
|
-
|
|
136
|
-
const sodax = new Sodax();
|
|
137
|
-
await sodax.config.initialize();
|
|
138
|
-
|
|
139
|
-
const result = await sodax.swaps.createIntent({
|
|
140
|
-
params: {
|
|
141
|
-
srcChainKey: ChainKeys.ARBITRUM_MAINNET,
|
|
142
|
-
dstChainKey: ChainKeys.STELLAR_MAINNET,
|
|
143
|
-
srcAddress: (await evmWallet.getWalletAddress()) as `0x${string}`,
|
|
144
|
-
/* … rest of intent params */
|
|
145
|
-
},
|
|
146
|
-
raw: false,
|
|
147
|
-
walletProvider: evmWallet,
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
if (!result.ok) {
|
|
151
|
-
console.error(result.error.toJSON());
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
console.log('intent created:', result.value.tx);
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
The chain key on the payload (`ChainKeys.ARBITRUM_MAINNET`) is what TypeScript narrows the wallet-provider parameter against — passing a Solana wallet would be a compile-time error. See [`architecture.md`](architecture.md) § 6 for the `WalletProviderSlot<K, Raw>` mechanism.
|
|
159
|
-
|
|
160
|
-
## 9. First-time troubleshooting
|
|
161
|
-
|
|
162
|
-
The errors most likely to hit on a fresh install or first port.
|
|
163
|
-
|
|
164
|
-
### "Cannot find module '@sodax/sdk' or its corresponding type declarations"
|
|
165
|
-
|
|
166
|
-
- TypeScript `moduleResolution` is `'node'` (legacy). Switch to `'bundler'` or `'node16'`/`'nodenext'`.
|
|
167
|
-
- Or: clear `node_modules` and reinstall. `@sodax/sdk` ships dual exports; resolution should be automatic.
|
|
168
|
-
|
|
169
|
-
### "Module '\"@sodax/sdk\"' has no exported member 'SONIC_MAINNET_CHAIN_ID'"
|
|
170
|
-
|
|
171
|
-
- v1 constant name. Use `ChainKeys.SONIC_MAINNET`. See [`../migration/breaking-changes/type-system.md`](../migration/breaking-changes/type-system.md) § 1.
|
|
172
|
-
|
|
173
|
-
### "Object literal may only specify known properties, and 'walletProvider' does not exist in type ..."
|
|
174
|
-
|
|
175
|
-
- Forgot `raw: false` (or `raw: true`) discriminator on the call. Add it. See [`architecture.md`](architecture.md) § 6.
|
|
176
|
-
|
|
177
|
-
### "Property 'tx' does not exist on type 'SwapResponse'" or similar
|
|
178
|
-
|
|
179
|
-
- You're treating the return as the success value directly instead of unpacking `result.value`. v2 returns `Promise<Result<T>>` — branch on `result.ok` first. See [`architecture.md`](architecture.md) § 7.
|
|
180
|
-
|
|
181
|
-
### `sodax.config.findSupportedTokenBySymbol` returns `undefined`
|
|
182
|
-
|
|
183
|
-
- `await sodax.config.initialize()` wasn't called. Add it after `new Sodax()`.
|
|
184
|
-
|
|
185
|
-
### "Property 'xChainId' does not exist on type 'XToken'"
|
|
186
|
-
|
|
187
|
-
- `XToken.xChainId` was renamed to `XToken.chainKey`. See [`../migration/breaking-changes/type-system.md`](../migration/breaking-changes/type-system.md) § 4.
|
|
188
|
-
|
|
189
|
-
### "Type '{ token, amount, action }' does not satisfy the expected type 'MoneyMarketSupplyParams'"
|
|
190
|
-
|
|
191
|
-
- Missing `srcChainKey` and `srcAddress` (required in v2). See [`features/money-market.md`](features/money-market.md).
|
|
192
|
-
|
|
193
|
-
### "Argument of type 'string' is not assignable to parameter of type 'GetAddressType<K>'"
|
|
194
|
-
|
|
195
|
-
- For EVM chains, `GetAddressType<K>` is `` `0x${string}` ``. Cast at the boundary: `(await walletProvider.getWalletAddress()) as \`0x${string}\``. See [`recipes/`](recipes/) § "Chain-key narrowing".
|
|
196
|
-
|
|
197
|
-
### `sodax.config.initialize()` hangs / errors
|
|
198
|
-
|
|
199
|
-
- The backend API is unreachable. The SDK should fall back to packaged defaults silently — check your network, then check that `SodaxConfig.backendApi.url` is correct (or omit it for the default).
|
|
200
|
-
|
|
201
|
-
### Stellar bridge / swap fails with `'Trustline missing'`
|
|
202
|
-
|
|
203
|
-
- Stellar destinations require a trustline for the destination asset before they can receive it. See [`chain-specifics.md`](chain-specifics.md) § "Stellar trustline".
|
|
204
|
-
|
|
205
|
-
---
|
|
206
|
-
|
|
207
|
-
## Cross-references
|
|
208
|
-
|
|
209
|
-
- v2 architecture: [`architecture.md`](architecture.md).
|
|
210
|
-
- Recipes for common patterns: [`recipes/`](recipes/).
|
|
211
|
-
- Per-feature usage: [`features/`](features/).
|
|
212
|
-
- Lookup tables (chain keys, error codes, public API): [`reference/`](reference/).
|
|
213
|
-
- v1 → v2 porting: [`../migration/README.md`](../migration/README.md).
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Recipes — `@sodax/sdk` v2
|
|
2
|
-
|
|
3
|
-
Copy-pasteable patterns for the most common Core SDK consumer tasks. Each file is self-contained — drop the snippet into your code, swap in your specifics, done.
|
|
4
|
-
|
|
5
|
-
| Recipe | When |
|
|
6
|
-
|---|---|
|
|
7
|
-
| [`initialize-sodax.md`](initialize-sodax.md) | App startup. `new Sodax()` + `await sodax.config.initialize()`, with and without config override. |
|
|
8
|
-
| [`result-and-errors.md`](result-and-errors.md) | Branching on `result.ok`, switching on `(error.feature, error.code)`, `isSodaxError` over `instanceof`, sub-Result propagation, logger integration. |
|
|
9
|
-
| [`signed-tx-flow.md`](signed-tx-flow.md) | `raw: false` + chain-narrowed `walletProvider`. Returns tx hash (or `TxHashPair` for cross-chain mutations). |
|
|
10
|
-
| [`raw-tx-flow.md`](raw-tx-flow.md) | `raw: true`. Builds an unsigned chain-specific payload; you sign elsewhere. |
|
|
11
|
-
| [`chain-key-narrowing.md`](chain-key-narrowing.md) | Cast-at-boundary pattern; runtime `chainType` discriminant. |
|
|
12
|
-
| [`testing.md`](testing.md) | Mocking the `Sodax` instance, stubbing the relay layer, `Result<T>` assertions. |
|
|
13
|
-
| [`gas-estimation.md`](gas-estimation.md) | Pre-flight gas estimation for raw-tx flows. |
|
|
14
|
-
| [`backend-server-init.md`](backend-server-init.md) | Node script / bot / partner backend pattern with `declare const` wallet placeholders. |
|
|
15
|
-
|
|
16
|
-
## Cross-references
|
|
17
|
-
|
|
18
|
-
- v2 architectural concepts: [`../architecture.md`](../architecture.md).
|
|
19
|
-
- Lookup tables (chain keys, error codes, public API): [`../reference/`](../reference/).
|
|
20
|
-
- DO / DO NOT / workflow: [`../ai-rules.md`](../ai-rules.md).
|
|
21
|
-
- v1 → v2 migration: [`../../migration/recipes.md`](../../migration/recipes.md).
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# Backend-server initialization (private-key)
|
|
2
|
-
|
|
3
|
-
Node script / bot / partner backend pattern. The `Sodax` instance holds no wallet itself — your application owns the `I*WalletProvider` object and passes it into each call.
|
|
4
|
-
|
|
5
|
-
```ts
|
|
6
|
-
import { Sodax, ChainKeys, type IEvmWalletProvider, type SpokeChainKey } from '@sodax/sdk';
|
|
7
|
-
|
|
8
|
-
declare const evmWallet: IEvmWalletProvider;
|
|
9
|
-
// ↑ Your application's wallet-provider object. Implement IEvmWalletProvider yourself,
|
|
10
|
-
// or install `@sodax/wallet-sdk-core` (separate package) which ships an `EvmWalletProvider`
|
|
11
|
-
// class you can construct with `{ privateKey, rpcUrl }`.
|
|
12
|
-
|
|
13
|
-
const sodax = new Sodax({
|
|
14
|
-
rpcConfig: {
|
|
15
|
-
[ChainKeys.ARBITRUM_MAINNET]: process.env.ARBITRUM_RPC_URL!,
|
|
16
|
-
[ChainKeys.SONIC_MAINNET]: process.env.SONIC_RPC_URL!,
|
|
17
|
-
// …
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
await sodax.config.initialize();
|
|
21
|
-
|
|
22
|
-
const result = await sodax.swaps.createIntent({
|
|
23
|
-
params: {
|
|
24
|
-
srcChainKey: ChainKeys.ARBITRUM_MAINNET,
|
|
25
|
-
dstChainKey: ChainKeys.STELLAR_MAINNET,
|
|
26
|
-
srcAddress: (await evmWallet.getWalletAddress()) as `0x${string}`,
|
|
27
|
-
/* … */
|
|
28
|
-
},
|
|
29
|
-
raw: false,
|
|
30
|
-
walletProvider: evmWallet,
|
|
31
|
-
});
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Multi-chain bots
|
|
35
|
-
|
|
36
|
-
If your bot operates on multiple source chains, hold one wallet provider per chain family and pick the right one at call time:
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
declare const wallets: {
|
|
40
|
-
readonly [ChainKeys.ARBITRUM_MAINNET]: IEvmWalletProvider;
|
|
41
|
-
readonly [ChainKeys.SONIC_MAINNET]: IEvmWalletProvider;
|
|
42
|
-
readonly [ChainKeys.SOLANA_MAINNET]: ISolanaWalletProvider;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
function getWallet(chainKey: SpokeChainKey) {
|
|
46
|
-
const wp = wallets[chainKey as keyof typeof wallets];
|
|
47
|
-
if (!wp) throw new Error(`No wallet configured for ${chainKey}`);
|
|
48
|
-
return wp;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
await sodax.swaps.createIntent({
|
|
52
|
-
params: { srcChainKey: ChainKeys.ARBITRUM_MAINNET, /* … */ },
|
|
53
|
-
raw: false,
|
|
54
|
-
walletProvider: getWallet(ChainKeys.ARBITRUM_MAINNET),
|
|
55
|
-
});
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Pitfall
|
|
59
|
-
|
|
60
|
-
Hold one wallet-provider instance per chain family for the lifetime of your process; don't recreate them per request. Implementations typically own an RPC client connection that's expensive to set up.
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
## Cross-references
|
|
66
|
-
|
|
67
|
-
- [`README.md`](README.md) — recipe index.
|
|
68
|
-
- [`../architecture.md`](../architecture.md) — concepts behind these patterns.
|
|
69
|
-
- [`../reference/`](../reference/) — chain keys, error codes, public API surface.
|