@sodax/sdk 2.0.0-rc.12 → 2.0.0-rc.13

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/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { getAbiItem, isAddress, toHex, hexToBytes, encodeAbiParameters, parseAbiParameters, defineChain, encodeFunctionData, erc20Abi as erc20Abi$1, createPublicClient, http, bytesToHex, keccak256, stringToBytes, fromHex, encodePacked, decodeAbiParameters, parseEventLogs, maxUint160, maxUint48 } from 'viem';
1
+ import { getAbiItem, parseAbi, isAddress, toHex, hexToBytes, encodeAbiParameters, parseAbiParameters, defineChain, encodeFunctionData, erc20Abi as erc20Abi$1, createPublicClient, http, bytesToHex, keccak256, stringToBytes, fromHex, encodePacked, decodeAbiParameters, parseEventLogs, maxUint160, maxUint48 } from 'viem';
2
2
  import { bcs } from '@mysten/sui/bcs';
3
3
  import { PublicKey, Connection, VersionedTransaction, SystemProgram, ComputeBudgetProgram, TransactionMessage, TransactionInstruction } from '@solana/web3.js';
4
4
  import { rpc, Address, xdr, Account, Horizon, Contract, TransactionBuilder, nativeToScVal, TimeoutInfinite, scValToBigInt, Operation, Asset, FeeBumpTransaction } from '@stellar/stellar-sdk';
@@ -169,7 +169,8 @@ var SODAX_FEATURES = [
169
169
  "migration",
170
170
  "dex",
171
171
  "partner",
172
- "recovery"
172
+ "recovery",
173
+ "leverageYield"
173
174
  ];
174
175
 
175
176
  // src/shared/utils/tiny-invariant.ts
@@ -531,6 +532,27 @@ var SodaTokens = {
531
532
  vault: "0x243b0c26c8b38793908d7C64e8510f21B19B4613"
532
533
  }
533
534
  };
535
+ var LsodaSymbols = ["lsodaWEETH", "lsodaWSTETH"];
536
+ var LsodaTokens = {
537
+ lsodaWEETH: {
538
+ symbol: "lsodaWEETH",
539
+ name: "Leveraged Soda weETH",
540
+ decimals: 18,
541
+ address: "0xD09de2f5070699A909c0FD32fb5A909d3886701D",
542
+ chainKey: ChainKeys.SONIC_MAINNET,
543
+ hubAsset: "0xD09de2f5070699A909c0FD32fb5A909d3886701D",
544
+ vault: "0xD09de2f5070699A909c0FD32fb5A909d3886701D"
545
+ },
546
+ lsodaWSTETH: {
547
+ symbol: "lsodaWSTETH",
548
+ name: "Leveraged Soda wstETH",
549
+ decimals: 18,
550
+ address: "0x136E5D1CEC5db1829E24941Eddd9C8640E02Ce7a",
551
+ chainKey: ChainKeys.SONIC_MAINNET,
552
+ hubAsset: "0x136E5D1CEC5db1829E24941Eddd9C8640E02Ce7a",
553
+ vault: "0x136E5D1CEC5db1829E24941Eddd9C8640E02Ce7a"
554
+ }
555
+ };
534
556
  var sonicSupportedTokens = {
535
557
  S: {
536
558
  symbol: "S",
@@ -595,7 +617,8 @@ var sonicSupportedTokens = {
595
617
  hubAsset: "0x7c7d53EEcda37a87ce0D5bf8E0b24512A48dC963",
596
618
  vault: SodaTokens.sodaSODA.address
597
619
  },
598
- ...SodaTokens
620
+ ...SodaTokens,
621
+ ...LsodaTokens
599
622
  };
600
623
  var redbellySupportedTokens = {
601
624
  RBNT: {
@@ -3596,7 +3619,8 @@ var swapSupportedTokens = {
3596
3619
  spokeChainConfig[ChainKeys.SONIC_MAINNET].supportedTokens.USDT,
3597
3620
  spokeChainConfig[ChainKeys.SONIC_MAINNET].supportedTokens.wS,
3598
3621
  spokeChainConfig[ChainKeys.SONIC_MAINNET].supportedTokens.SODA,
3599
- ...Object.values(SodaTokens)
3622
+ ...Object.values(SodaTokens),
3623
+ ...Object.values(LsodaTokens)
3600
3624
  ],
3601
3625
  [ChainKeys.AVALANCHE_MAINNET]: [
3602
3626
  spokeChainConfig[ChainKeys.AVALANCHE_MAINNET].supportedTokens.AVAX,
@@ -3836,6 +3860,41 @@ var swapsConfig = {
3836
3860
  var getSupportedSolverTokens = (chainId) => swapSupportedTokens[chainId];
3837
3861
  var isSwapSupportedToken = (chainId, token) => swapSupportedTokens[chainId].some((t) => t.address.toLowerCase() === token.toLowerCase());
3838
3862
 
3863
+ // ../types/dist/leverageYield/leverageYield.js
3864
+ var leverageYieldVaults = [
3865
+ {
3866
+ name: LsodaTokens.lsodaWEETH.symbol,
3867
+ vault: LsodaTokens.lsodaWEETH.vault,
3868
+ asset: SodaTokens.sodaWEETH.address,
3869
+ // sodaWEETH on Sonic
3870
+ borrowToken: SodaTokens.sodaETH.address,
3871
+ // sodaETH on Sonic
3872
+ lsdSource: {
3873
+ // DefiLlama pool for EtherFi's weETH on Ethereum (project: 'ether.fi-stake').
3874
+ poolId: "46bd2bdf-6d92-4066-b482-e885ee172264",
3875
+ fallbackAprPct: 3,
3876
+ label: "EtherFi (weETH)"
3877
+ }
3878
+ },
3879
+ {
3880
+ name: LsodaTokens.lsodaWSTETH.symbol,
3881
+ vault: LsodaTokens.lsodaWSTETH.vault,
3882
+ asset: SodaTokens.sodaWSTETH.address,
3883
+ // sodaWSTETH on Sonic
3884
+ borrowToken: SodaTokens.sodaETH.address,
3885
+ // sodaETH on Sonic
3886
+ lsdSource: {
3887
+ // DefiLlama pool for Lido's stETH on Ethereum (wstETH inherits this rate via redeem).
3888
+ poolId: "747c1d2a-c668-4682-b9f9-296708a3dd90",
3889
+ fallbackAprPct: 2.4,
3890
+ label: "Lido (stETH)"
3891
+ }
3892
+ }
3893
+ ];
3894
+ var leverageYieldConfig = {
3895
+ vaults: leverageYieldVaults
3896
+ };
3897
+
3839
3898
  // ../types/dist/sodax-config/sodax-config.js
3840
3899
  var bridgeConfig = {
3841
3900
  partnerFee: void 0
@@ -3847,6 +3906,7 @@ var sodaxConfig = {
3847
3906
  moneyMarket: moneyMarketConfig,
3848
3907
  bridge: bridgeConfig,
3849
3908
  dex: dexConfig,
3909
+ leverageYield: leverageYieldConfig,
3850
3910
  hub: hubConfig,
3851
3911
  api: apiConfig,
3852
3912
  solver: solverConfig,
@@ -3988,7 +4048,7 @@ function isValidWalletProviderForChainKey(chainKey, walletProvider) {
3988
4048
  }
3989
4049
 
3990
4050
  // ../types/dist/index.js
3991
- var CONFIG_VERSION = 210;
4051
+ var CONFIG_VERSION = 211;
3992
4052
  function isEvmSpokeChainConfig(value) {
3993
4053
  return typeof value === "object" && value !== null && value.chain.type === "EVM" && value.chain.key !== HUB_CHAIN_KEY;
3994
4054
  }
@@ -22267,17 +22327,11 @@ var SuiSpokeService = class {
22267
22327
  ]
22268
22328
  });
22269
22329
  if (params.raw === true) {
22270
- tx.setSender(from);
22271
- const transactionRaw = await tx.build({
22272
- client: this.publicClient,
22273
- onlyTransactionKind: true
22274
- });
22275
- const transactionRawBase64String = Buffer.from(transactionRaw).toString("base64");
22276
22330
  return {
22277
22331
  from,
22278
22332
  to: `${assetManager.packageId}::${assetManager.moduleId}::transfer`,
22279
22333
  value: amount,
22280
- data: transactionRawBase64String
22334
+ data: tx.serialize()
22281
22335
  };
22282
22336
  }
22283
22337
  return params.walletProvider.signAndExecuteTxn(tx);
@@ -22297,17 +22351,11 @@ var SuiSpokeService = class {
22297
22351
  ]
22298
22352
  });
22299
22353
  if (params.raw === true) {
22300
- txb.setSender(from);
22301
- const transactionRaw = await txb.build({
22302
- client: this.publicClient,
22303
- onlyTransactionKind: true
22304
- });
22305
- const transactionRawBase64String = Buffer.from(transactionRaw).toString("base64");
22306
22354
  return {
22307
22355
  from,
22308
22356
  to: `${connection.packageId}::${connection.moduleId}::send_message_ua`,
22309
22357
  value: 0n,
22310
- data: transactionRawBase64String
22358
+ data: txb.serialize()
22311
22359
  };
22312
22360
  }
22313
22361
  return params.walletProvider.signAndExecuteTxn(txb);
@@ -22318,7 +22366,7 @@ var SuiSpokeService = class {
22318
22366
  * @returns {Promise<bigint>} The estimated computation cost.
22319
22367
  */
22320
22368
  async estimateGas({ tx }) {
22321
- const txb = Transaction$1.fromKind(tx.data);
22369
+ const txb = Transaction$1.from(tx.data);
22322
22370
  const result = await this.publicClient.devInspectTransactionBlock({
22323
22371
  sender: tx.from,
22324
22372
  transactionBlock: txb
@@ -22549,6 +22597,7 @@ var CustomStellarAccount = class {
22549
22597
  decrementSequenceNumber() {
22550
22598
  if (this.sequenceNumber > this.startingSequenceNumber) {
22551
22599
  this.sequenceNumber--;
22600
+ return;
22552
22601
  }
22553
22602
  throw new Error(
22554
22603
  `Sequence number cannot be decremented below the starting sequence number: ${this.startingSequenceNumber}`
@@ -22655,7 +22704,7 @@ var StellarSpokeService = class {
22655
22704
  );
22656
22705
  const assembledPriorityTx = rpc.assembleTransaction(rawPriorityTx, simulation).build();
22657
22706
  if (params.raw) {
22658
- const transactionXdr = rawPriorityTx.toXDR();
22707
+ const transactionXdr = assembledPriorityTx.toXDR();
22659
22708
  return {
22660
22709
  from,
22661
22710
  to: this.config.getChainConfig(srcChainKey).addresses.assetManager,
@@ -22772,7 +22821,7 @@ var StellarSpokeService = class {
22772
22821
  );
22773
22822
  const assembledPriorityTx = rpc.assembleTransaction(rawPriorityTx, simulation).build();
22774
22823
  if (params.raw) {
22775
- const transactionXdr = rawPriorityTx.toXDR();
22824
+ const transactionXdr = assembledPriorityTx.toXDR();
22776
22825
  return {
22777
22826
  from,
22778
22827
  to: this.config.getChainConfig(srcChainKey).addresses.assetManager,
@@ -36985,7 +37034,12 @@ var RecoveryService = class {
36985
37034
  srcChainKey: chainKey,
36986
37035
  field: "chainKey"
36987
37036
  });
36988
- const entries = Object.values(chainConfig.supportedTokens).filter((token) => isAddress(token.hubAsset));
37037
+ const leverageVaultAddresses = new Set(
37038
+ this.config.sodaxConfig.leverageYield.vaults.map((vault) => vault.vault.toLowerCase())
37039
+ );
37040
+ const entries = Object.values(chainConfig.supportedTokens).filter(
37041
+ (token) => isAddress(token.hubAsset) && !leverageVaultAddresses.has(token.hubAsset.toLowerCase())
37042
+ );
36989
37043
  if (entries.length === 0) {
36990
37044
  return { ok: true, value: [] };
36991
37045
  }
@@ -37087,6 +37141,871 @@ var RecoveryService = class {
37087
37141
  }
37088
37142
  };
37089
37143
 
37144
+ // src/leverageYield/errors.ts
37145
+ var leverageYieldInvariant = createInvariant("leverageYield");
37146
+ var LEVERAGE_YIELD_CODES = /* @__PURE__ */ new Set([
37147
+ "VALIDATION_FAILED",
37148
+ "INTENT_CREATION_FAILED",
37149
+ "APPROVE_FAILED",
37150
+ "ALLOWANCE_CHECK_FAILED",
37151
+ "LOOKUP_FAILED",
37152
+ "TX_VERIFICATION_FAILED",
37153
+ "TX_SUBMIT_FAILED",
37154
+ "RELAY_TIMEOUT",
37155
+ "RELAY_FAILED",
37156
+ "EXECUTION_FAILED",
37157
+ "EXTERNAL_API_ERROR",
37158
+ "UNKNOWN"
37159
+ ]);
37160
+ var LEVERAGE_YIELD_POST_EXECUTION_CODES = /* @__PURE__ */ new Set([
37161
+ "EXECUTION_FAILED",
37162
+ "EXTERNAL_API_ERROR",
37163
+ "UNKNOWN"
37164
+ ]);
37165
+ var LEVERAGE_YIELD_SWAP_CODES = /* @__PURE__ */ new Set([
37166
+ "VALIDATION_FAILED",
37167
+ "INTENT_CREATION_FAILED",
37168
+ "TX_VERIFICATION_FAILED",
37169
+ "TX_SUBMIT_FAILED",
37170
+ "RELAY_TIMEOUT",
37171
+ "RELAY_FAILED",
37172
+ "EXECUTION_FAILED",
37173
+ "EXTERNAL_API_ERROR",
37174
+ "UNKNOWN"
37175
+ ]);
37176
+ var isLeverageYieldCreateIntentError = isCodeMember(CREATE_INTENT_CODES);
37177
+ var isLeverageYieldApproveError = isCodeMember(APPROVE_CODES);
37178
+ var isLeverageYieldAllowanceCheckError = isCodeMember(ALLOWANCE_CHECK_CODES);
37179
+ var isLeverageYieldLookupError = isCodeMember(LOOKUP_CODES);
37180
+ var isLeverageYieldPostExecutionError = isCodeMember(
37181
+ LEVERAGE_YIELD_POST_EXECUTION_CODES
37182
+ );
37183
+ var isLeverageYieldSwapError = isCodeMember(LEVERAGE_YIELD_SWAP_CODES);
37184
+ var isLeverageYieldError = isCodeMember(LEVERAGE_YIELD_CODES);
37185
+
37186
+ // src/leverageYield/LeverageYieldService.ts
37187
+ var leverageYieldVaultAbi = parseAbi([
37188
+ "function asset() view returns (address)",
37189
+ "function getPositionDetails() view returns (uint256 collateral, uint256 debt, uint256 ltv, uint256 healthFactor, uint256 idleAsset)",
37190
+ // Used by getApr() — read-only metadata that doesn't change per pass.
37191
+ "function pool() view returns (address)",
37192
+ "function borrowToken() view returns (address)",
37193
+ "function targetLTV() view returns (uint256)"
37194
+ ]);
37195
+ var INTENT_DEADLINE_BUFFER_SECONDS = 5 * 60;
37196
+ var ANY_SOLVER_ADDRESS = "0x0000000000000000000000000000000000000000";
37197
+ var MAX_WITHDRAW_DUST_BUFFER = 1000n;
37198
+ function pctToRay(aprPct) {
37199
+ return BigInt(Math.round(aprPct * 1e9)) * 10n ** 16n;
37200
+ }
37201
+ var DEFILLAMA_FETCH_TIMEOUT_MS = 1e4;
37202
+ var DEFILLAMA_FETCH_MAX_ATTEMPTS = 2;
37203
+ async function fetchWithTimeout(url, timeoutMs) {
37204
+ const controller = new AbortController();
37205
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
37206
+ try {
37207
+ return await fetch(url, { signal: controller.signal });
37208
+ } finally {
37209
+ clearTimeout(timeoutId);
37210
+ }
37211
+ }
37212
+ async function fetchDefillamaApr(poolId) {
37213
+ return retry(async () => {
37214
+ const response = await fetchWithTimeout(`https://yields.llama.fi/chart/${poolId}`, DEFILLAMA_FETCH_TIMEOUT_MS);
37215
+ if (!response.ok) throw new Error(`DefiLlama APR fetch failed: HTTP ${response.status}`);
37216
+ const json = await response.json();
37217
+ const series = json?.data;
37218
+ if (!Array.isArray(series) || series.length === 0) {
37219
+ throw new Error("DefiLlama APR response: empty time series");
37220
+ }
37221
+ const latest = series[series.length - 1]?.apy;
37222
+ if (typeof latest !== "number") throw new Error("DefiLlama APR: latest entry missing numeric apy");
37223
+ return latest;
37224
+ }, DEFILLAMA_FETCH_MAX_ATTEMPTS);
37225
+ }
37226
+ var LeverageYieldService = class {
37227
+ hubProvider;
37228
+ config;
37229
+ spoke;
37230
+ constructor({ hubProvider, config, spoke }) {
37231
+ this.hubProvider = hubProvider;
37232
+ this.config = config;
37233
+ this.spoke = spoke;
37234
+ }
37235
+ // ─── Registry ──────────────────────────────────────────────────────────
37236
+ /** Returns the static registry of known leverage-yield vaults. */
37237
+ listVaults() {
37238
+ return this.config.sodaxConfig.leverageYield.vaults;
37239
+ }
37240
+ /** Looks up a vault by its `name` field. Returns `undefined` when not registered. */
37241
+ getVault(name) {
37242
+ return this.listVaults().find((v) => v.name === name);
37243
+ }
37244
+ /**
37245
+ * Looks up a registered vault by its on-chain proxy address (case-insensitive).
37246
+ * Returns `undefined` when the address isn't in the registry.
37247
+ */
37248
+ getVaultByAddress(address) {
37249
+ const normalized = address.toLowerCase();
37250
+ return this.listVaults().find((v) => v.vault.toLowerCase() === normalized);
37251
+ }
37252
+ /**
37253
+ * Resolves the intent `deadline`: returns the caller-supplied value verbatim, otherwise
37254
+ * derives a default from the hub-chain (Sonic) block timestamp plus
37255
+ * {@link INTENT_DEADLINE_BUFFER_SECONDS}. The deadline is enforced on-chain against the hub
37256
+ * block time, so the default is anchored to that block — never the client clock, which can
37257
+ * drift and produce an already-expired or over-extended deadline.
37258
+ *
37259
+ * Returns a {@link Result}: a `getBlock` RPC outage is a read failure, surfaced as
37260
+ * `LOOKUP_FAILED` (`method: 'resolveDeadline'`) rather than masquerading as an intent-build
37261
+ * failure. The `deposit` / `withdraw` callers forward it verbatim.
37262
+ */
37263
+ async resolveDeadline(deadline, srcChainKey) {
37264
+ if (deadline !== void 0) return { ok: true, value: deadline };
37265
+ try {
37266
+ const block = await this.hubProvider.publicClient.getBlock({
37267
+ includeTransactions: false,
37268
+ blockTag: "latest"
37269
+ });
37270
+ return { ok: true, value: block.timestamp + BigInt(INTENT_DEADLINE_BUFFER_SECONDS) };
37271
+ } catch (error) {
37272
+ return { ok: false, error: lookupFailed("leverageYield", "resolveDeadline", error, { srcChainKey }) };
37273
+ }
37274
+ }
37275
+ /**
37276
+ * Builds the {@link LeverageYieldSwapPayload} for a leverage-yield deposit (any token → lsoda*).
37277
+ * The lsoda* output is delivered to the user's hub wallet on Sonic so a later
37278
+ * {@link LeverageYieldService.withdraw} can swap it back. Spread the result into
37279
+ * {@link LeverageYieldService.vaultSwap}: `vaultSwap({ ...payload, walletProvider })`.
37280
+ * An optional `partnerFee` is forwarded on the payload as the per-intent fee override.
37281
+ *
37282
+ * For `minOutputAmount`, quote via `sodax.swaps.getQuote` with the vault address as the
37283
+ * destination token (`token_dst`) — vault shares are solver-tradeable, so the generic swap
37284
+ * quote applies; then subtract your slippage tolerance.
37285
+ */
37286
+ async deposit(params) {
37287
+ const baseCtx = { srcChainKey: params.srcChainKey, action: "deposit" };
37288
+ try {
37289
+ leverageYieldInvariant(params.inputAmount > 0n, "inputAmount must be greater than 0", {
37290
+ ...baseCtx,
37291
+ field: "inputAmount"
37292
+ });
37293
+ leverageYieldInvariant(params.vault.length > 0, "Vault address is required", { ...baseCtx, field: "vault" });
37294
+ leverageYieldInvariant(params.inputToken.length > 0, "inputToken is required", {
37295
+ ...baseCtx,
37296
+ field: "inputToken"
37297
+ });
37298
+ const hubWallet = await this.hubProvider.getUserHubWalletAddress(params.srcAddress, params.srcChainKey);
37299
+ const deadlineResult = await this.resolveDeadline(params.deadline, params.srcChainKey);
37300
+ if (!deadlineResult.ok) return deadlineResult;
37301
+ const deadline = deadlineResult.value;
37302
+ return {
37303
+ ok: true,
37304
+ value: {
37305
+ params: {
37306
+ inputToken: params.inputToken,
37307
+ outputToken: params.vault,
37308
+ inputAmount: params.inputAmount,
37309
+ minOutputAmount: params.minOutputAmount,
37310
+ deadline,
37311
+ allowPartialFill: false,
37312
+ srcChainKey: params.srcChainKey,
37313
+ dstChainKey: this.hubProvider.chainConfig.chain.key,
37314
+ srcAddress: params.srcAddress,
37315
+ dstAddress: hubWallet,
37316
+ solver: params.solver ?? ANY_SOLVER_ADDRESS,
37317
+ data: "0x"
37318
+ },
37319
+ // Per-intent fee override — only included when the caller supplies one, so the
37320
+ // payload stays free of undefined-valued keys.
37321
+ ...params.partnerFee !== void 0 && { partnerFee: params.partnerFee }
37322
+ }
37323
+ };
37324
+ } catch (error) {
37325
+ if (isLeverageYieldCreateIntentError(error)) return { ok: false, error };
37326
+ return { ok: false, error: intentCreationFailed("leverageYield", error, baseCtx) };
37327
+ }
37328
+ }
37329
+ /**
37330
+ * Builds the {@link LeverageYieldSwapPayload} for a leverage-yield withdraw (lsoda* → any
37331
+ * token). The payload carries `hubWalletSwap: true` — {@link LeverageYieldService.vaultSwap}
37332
+ * then spends the lsoda* held in the user's hub wallet by authorising it via a
37333
+ * `Connection.sendMessage` the user signs on `srcChainKey`. Wrapped in a {@link Result} for
37334
+ * a call shape uniform with {@link LeverageYieldService.deposit}; async because the default
37335
+ * `deadline` is read from the hub block timestamp.
37336
+ *
37337
+ * For `minOutputAmount`, quote via `sodax.swaps.getQuote` with the vault address as the
37338
+ * source token (`token_src`) — vault shares are solver-tradeable, so the generic swap quote
37339
+ * applies; then subtract your slippage tolerance.
37340
+ */
37341
+ async withdraw(params) {
37342
+ const baseCtx = { srcChainKey: params.srcChainKey, action: "withdraw" };
37343
+ try {
37344
+ leverageYieldInvariant(params.inputAmount > 0n, "inputAmount must be greater than 0", {
37345
+ ...baseCtx,
37346
+ field: "inputAmount"
37347
+ });
37348
+ leverageYieldInvariant(params.vault.length > 0, "Vault address is required", { ...baseCtx, field: "vault" });
37349
+ leverageYieldInvariant(params.outputToken.length > 0, "outputToken is required", {
37350
+ ...baseCtx,
37351
+ field: "outputToken"
37352
+ });
37353
+ const deadlineResult = await this.resolveDeadline(params.deadline, params.srcChainKey);
37354
+ if (!deadlineResult.ok) return deadlineResult;
37355
+ const deadline = deadlineResult.value;
37356
+ return {
37357
+ ok: true,
37358
+ value: {
37359
+ params: {
37360
+ inputToken: params.vault,
37361
+ outputToken: params.outputToken,
37362
+ inputAmount: params.inputAmount,
37363
+ minOutputAmount: params.minOutputAmount,
37364
+ deadline,
37365
+ allowPartialFill: false,
37366
+ srcChainKey: params.srcChainKey,
37367
+ dstChainKey: params.dstChainKey,
37368
+ srcAddress: params.srcAddress,
37369
+ dstAddress: params.recipient ?? params.srcAddress,
37370
+ solver: params.solver ?? ANY_SOLVER_ADDRESS,
37371
+ data: "0x"
37372
+ },
37373
+ hubWalletSwap: true
37374
+ }
37375
+ };
37376
+ } catch (error) {
37377
+ if (isLeverageYieldCreateIntentError(error)) return { ok: false, error };
37378
+ return { ok: false, error: intentCreationFailed("leverageYield", error, baseCtx) };
37379
+ }
37380
+ }
37381
+ /**
37382
+ * Creates a vault swap intent on the user's source spoke chain without submitting it to
37383
+ * the solver. Leverage-yield copy of the swap domain's `createIntent`, specialised for
37384
+ * vault flows — duplicated deliberately so the vault-specific execution modifiers
37385
+ * (`hubWalletSwap`, per-intent `partnerFee`) stay off the generic swap surface.
37386
+ *
37387
+ * Use {@link LeverageYieldService.vaultSwap} for the full end-to-end flow
37388
+ * (create → relay → notify solver); use this directly when you need the raw transaction
37389
+ * or drive the relay yourself (e.g. the backend submit-tx path). To complete a manual flow,
37390
+ * relay the returned `relayData` (the shared `relayTxAndWaitPacket` helper) and then call
37391
+ * {@link LeverageYieldService.notifySolver} with the hub-side intent tx hash.
37392
+ *
37393
+ * @param _params - Intent parameters, source chain key, wallet provider (when `raw: false`),
37394
+ * and optional `skipSimulation` / `hubWalletSwap` / `partnerFee`.
37395
+ * @returns A `Result<CreateVaultIntentResult<K, Raw>, LeverageYieldCreateIntentError>`.
37396
+ * On success contains:
37397
+ * - `tx` — chain-specific tx hash (executed) or raw tx data (raw mode).
37398
+ * - `intent` — the fully constructed `Intent` object augmented with `feeAmount`.
37399
+ * - `relayData` — `{ address, payload }` needed to submit the intent to the relayer.
37400
+ *
37401
+ * On failure `result.error` is a SodaxError with `VALIDATION_FAILED` (invariant
37402
+ * precondition), `INTENT_CREATION_FAILED` (spoke-side creation/deposit failed) or
37403
+ * `UNKNOWN` (defensive fallback).
37404
+ */
37405
+ async createVaultIntent(_params) {
37406
+ const { params, skipSimulation, hubWalletSwap, partnerFee = this.config.swaps.partnerFee } = _params;
37407
+ const baseCtx = { srcChainKey: params.srcChainKey, dstChainKey: params.dstChainKey };
37408
+ try {
37409
+ leverageYieldInvariant(
37410
+ isUndefinedOrValidWalletProviderForChainKey(params.srcChainKey, _params.walletProvider),
37411
+ `Invalid wallet provider for chain key: ${params.srcChainKey}`,
37412
+ baseCtx
37413
+ );
37414
+ const hubChainKey = this.hubProvider.chainConfig.chain.key;
37415
+ const inputTokenChainKey = hubWalletSwap ? hubChainKey : params.srcChainKey;
37416
+ leverageYieldInvariant(
37417
+ this.config.isValidOriginalAssetAddress(inputTokenChainKey, params.inputToken),
37418
+ `Unsupported spoke chain token (srcChainKey: ${inputTokenChainKey}, inputToken: ${params.inputToken})`,
37419
+ { ...baseCtx, field: "inputToken" }
37420
+ );
37421
+ leverageYieldInvariant(
37422
+ this.config.isValidOriginalAssetAddress(params.dstChainKey, params.outputToken),
37423
+ `Unsupported spoke chain token (params.dstChain: ${params.dstChainKey}, params.outputToken: ${params.outputToken})`,
37424
+ { ...baseCtx, field: "outputToken" }
37425
+ );
37426
+ leverageYieldInvariant(
37427
+ this.config.isValidSpokeChainKey(params.srcChainKey),
37428
+ `Invalid spoke chain (srcChainKey): ${params.srcChainKey}`,
37429
+ { ...baseCtx, field: "srcChainKey" }
37430
+ );
37431
+ leverageYieldInvariant(
37432
+ this.config.isValidSpokeChainKey(params.dstChainKey),
37433
+ `Invalid spoke chain (params.dstChain): ${params.dstChainKey}`,
37434
+ { ...baseCtx, field: "dstChainKey" }
37435
+ );
37436
+ if (isBitcoinChainKey(params.dstChainKey) && params.outputToken === "BTC") {
37437
+ leverageYieldInvariant(
37438
+ params.minOutputAmount >= 546n,
37439
+ `Invalid minOutputAmount (params.minOutputAmount): ${params.minOutputAmount}`,
37440
+ { ...baseCtx, field: "minOutputAmount" }
37441
+ );
37442
+ }
37443
+ const personalAddress = params.srcAddress;
37444
+ let walletAddress = personalAddress;
37445
+ if (isBitcoinChainKeyType(params.srcChainKey) && _params.raw === false) {
37446
+ leverageYieldInvariant(
37447
+ isBitcoinWalletProviderType(_params.walletProvider),
37448
+ `Invalid wallet provider for chain key: ${params.srcChainKey}`,
37449
+ baseCtx
37450
+ );
37451
+ walletAddress = await this.spoke.bitcoin.getEffectiveWalletAddress(personalAddress);
37452
+ await this.spoke.bitcoin.radfi.ensureRadfiAccessToken(_params.walletProvider);
37453
+ }
37454
+ const creatorHubWalletAddress = await this.hubProvider.getUserHubWalletAddress(walletAddress, params.srcChainKey);
37455
+ if (hubWalletSwap) {
37456
+ const [data2, intent2, feeAmount2] = EvmSolverService.constructCreateIntentData(
37457
+ { ...params, srcChainKey: hubChainKey, srcAddress: creatorHubWalletAddress },
37458
+ creatorHubWalletAddress,
37459
+ this.config,
37460
+ partnerFee
37461
+ );
37462
+ const coreSendMessageParams = {
37463
+ srcChainKey: params.srcChainKey,
37464
+ // Personal address — NOT the resolved trading `walletAddress`. SpokeService.sendMessage
37465
+ // re-resolves the effective (Bitcoin trading) address itself; passing the already-resolved
37466
+ // trading address here would double-resolve it (getTradingWallet(tradingAddress) →
37467
+ // "Trading wallet not found"). The trading address is used only for the hub-wallet
37468
+ // derivation above (creatorHubWalletAddress). Mirrors MoneyMarketService borrow/withdraw.
37469
+ srcAddress: personalAddress,
37470
+ dstChainKey: hubChainKey,
37471
+ dstAddress: creatorHubWalletAddress,
37472
+ payload: data2,
37473
+ skipSimulation
37474
+ };
37475
+ const txResult2 = await this.spoke.sendMessage(
37476
+ _params.raw ? { ...coreSendMessageParams, raw: true } : {
37477
+ ...coreSendMessageParams,
37478
+ raw: false,
37479
+ walletProvider: _params.walletProvider
37480
+ }
37481
+ );
37482
+ if (!txResult2.ok) {
37483
+ if (isLeverageYieldCreateIntentError(txResult2.error)) {
37484
+ return { ok: false, error: txResult2.error };
37485
+ }
37486
+ return { ok: false, error: intentCreationFailed("leverageYield", txResult2.error, baseCtx) };
37487
+ }
37488
+ return {
37489
+ ok: true,
37490
+ value: {
37491
+ tx: txResult2.value,
37492
+ intent: { ...intent2, feeAmount: feeAmount2 },
37493
+ relayData: { address: creatorHubWalletAddress, payload: data2 }
37494
+ }
37495
+ };
37496
+ }
37497
+ if (isHubChainKeyType(params.srcChainKey) && isSonicChainKeyType(params.srcChainKey)) {
37498
+ const coreSonicParams = {
37499
+ createIntentParams: params,
37500
+ creatorHubWalletAddress,
37501
+ solverConfig: this.config.solver,
37502
+ fee: partnerFee,
37503
+ hubProvider: this.hubProvider
37504
+ };
37505
+ const [txResult2, intent2, feeAmount2, data2] = await SonicSpokeService.createSwapIntent(
37506
+ _params.raw ? { ...coreSonicParams, raw: true } : {
37507
+ ...coreSonicParams,
37508
+ raw: false,
37509
+ walletProvider: _params.walletProvider
37510
+ }
37511
+ );
37512
+ return {
37513
+ ok: true,
37514
+ value: {
37515
+ tx: txResult2,
37516
+ intent: { ...intent2, feeAmount: feeAmount2 },
37517
+ relayData: { address: intent2.creator, payload: data2 }
37518
+ }
37519
+ };
37520
+ }
37521
+ const [data, intent, feeAmount] = EvmSolverService.constructCreateIntentData(
37522
+ {
37523
+ ...params,
37524
+ srcAddress: walletAddress
37525
+ },
37526
+ creatorHubWalletAddress,
37527
+ this.config,
37528
+ partnerFee
37529
+ );
37530
+ const coreDepositParams = {
37531
+ srcChainKey: params.srcChainKey,
37532
+ srcAddress: walletAddress,
37533
+ to: creatorHubWalletAddress,
37534
+ token: params.inputToken,
37535
+ amount: params.inputAmount,
37536
+ data,
37537
+ skipSimulation
37538
+ };
37539
+ const txResult = await this.spoke.deposit(
37540
+ _params.raw ? {
37541
+ ...coreDepositParams,
37542
+ raw: true
37543
+ } : {
37544
+ ...coreDepositParams,
37545
+ raw: false,
37546
+ walletProvider: _params.walletProvider
37547
+ }
37548
+ );
37549
+ if (!txResult.ok) {
37550
+ if (isLeverageYieldCreateIntentError(txResult.error)) {
37551
+ return { ok: false, error: txResult.error };
37552
+ }
37553
+ return {
37554
+ ok: false,
37555
+ error: intentCreationFailed("leverageYield", txResult.error, baseCtx)
37556
+ };
37557
+ }
37558
+ return {
37559
+ ok: true,
37560
+ value: {
37561
+ tx: txResult.value,
37562
+ intent: { ...intent, feeAmount },
37563
+ relayData: { address: intent.creator, payload: data }
37564
+ }
37565
+ };
37566
+ } catch (error) {
37567
+ if (isLeverageYieldCreateIntentError(error)) return { ok: false, error };
37568
+ return {
37569
+ ok: false,
37570
+ error: intentCreationFailed("leverageYield", error, baseCtx)
37571
+ };
37572
+ }
37573
+ }
37574
+ /**
37575
+ * Executes a full end-to-end leverage-yield vault swap (deposit or withdraw).
37576
+ * Leverage-yield copy of the swap domain's `swap()` orchestrator:
37577
+ * 1. Calls {@link LeverageYieldService.createVaultIntent} to submit the intent
37578
+ * transaction on the source spoke chain.
37579
+ * 2. Verifies the spoke transaction landed on-chain.
37580
+ * 3. For non-hub source chains: submits the spoke tx to the relayer and waits for the
37581
+ * relay packet to land on the hub (Sonic). Skipped when `srcChainKey` is the hub.
37582
+ * 4. Notifies the solver, triggering it to fill the intent.
37583
+ *
37584
+ * Spread a {@link LeverageYieldSwapPayload} from `deposit` / `withdraw` into this method
37585
+ * alongside the wallet provider: `vaultSwap({ ...payload, walletProvider })`.
37586
+ *
37587
+ * @returns A `Result<VaultSwapResponse, LeverageYieldSwapError>`. On success:
37588
+ * - `solverExecutionResponse` — solver acknowledgement (`{ answer: 'OK', intent_hash }`).
37589
+ * - `intent` — the on-chain intent object that was created.
37590
+ * - `intentDeliveryInfo` — source/destination chain keys, tx hashes, and user addresses.
37591
+ *
37592
+ * On failure `result.error` carries one of the create-intent codes plus
37593
+ * `TX_VERIFICATION_FAILED`, `TX_SUBMIT_FAILED`, `RELAY_TIMEOUT`, `RELAY_FAILED`,
37594
+ * `EXECUTION_FAILED`, `EXTERNAL_API_ERROR` or `UNKNOWN`.
37595
+ */
37596
+ async vaultSwap(_params) {
37597
+ const { params } = _params;
37598
+ const srcChainKey = params.srcChainKey;
37599
+ const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "vaultSwap" };
37600
+ try {
37601
+ const timeout = _params.timeout;
37602
+ const createIntentResult = await this.createVaultIntent(_params);
37603
+ if (!createIntentResult.ok) {
37604
+ return { ok: false, error: createIntentResult.error };
37605
+ }
37606
+ const { tx: spokeTxHash, intent, relayData } = createIntentResult.value;
37607
+ const verifyTxHashResult = await this.spoke.verifyTxHash({
37608
+ txHash: spokeTxHash,
37609
+ chainKey: srcChainKey
37610
+ });
37611
+ if (!verifyTxHashResult.ok) {
37612
+ return {
37613
+ ok: false,
37614
+ error: verifyFailed("leverageYield", verifyTxHashResult.error, baseCtx)
37615
+ };
37616
+ }
37617
+ let dstIntentTxHash;
37618
+ if (isHubChainKeyType(srcChainKey)) {
37619
+ dstIntentTxHash = spokeTxHash;
37620
+ } else {
37621
+ const packet = await relayTxAndWaitPacket({
37622
+ srcTxHash: spokeTxHash,
37623
+ data: relayData,
37624
+ chainKey: srcChainKey,
37625
+ relayerApiEndpoint: this.config.relay.relayerApiEndpoint,
37626
+ timeout
37627
+ });
37628
+ if (!packet.ok) {
37629
+ return {
37630
+ ok: false,
37631
+ error: mapRelayFailure(packet.error, { feature: "leverageYield", ...baseCtx })
37632
+ };
37633
+ }
37634
+ dstIntentTxHash = packet.value.dst_tx_hash;
37635
+ }
37636
+ const postExecResult = await this.notifySolver({
37637
+ intent_tx_hash: dstIntentTxHash
37638
+ });
37639
+ if (!postExecResult.ok) {
37640
+ return { ok: false, error: postExecResult.error };
37641
+ }
37642
+ return {
37643
+ ok: true,
37644
+ value: {
37645
+ solverExecutionResponse: postExecResult.value,
37646
+ intent,
37647
+ intentDeliveryInfo: {
37648
+ srcChainKey,
37649
+ srcTxHash: spokeTxHash,
37650
+ srcAddress: params.srcAddress,
37651
+ dstChainKey: params.dstChainKey,
37652
+ dstTxHash: dstIntentTxHash,
37653
+ dstAddress: params.dstAddress
37654
+ }
37655
+ }
37656
+ };
37657
+ } catch (error) {
37658
+ if (isLeverageYieldSwapError(error)) return { ok: false, error };
37659
+ return {
37660
+ ok: false,
37661
+ error: unknownFailed("leverageYield", error, baseCtx)
37662
+ };
37663
+ }
37664
+ }
37665
+ /**
37666
+ * Notifies the solver that the vault intent landed on the hub, triggering it to fill.
37667
+ * Leverage-yield copy of the swap domain's `postExecution` — emits only
37668
+ * `EXECUTION_FAILED` / `EXTERNAL_API_ERROR` / `UNKNOWN` (relay/verify codes appear only
37669
+ * on {@link LeverageYieldService.vaultSwap}, which owns the verify + relay steps).
37670
+ *
37671
+ * Called automatically by {@link LeverageYieldService.vaultSwap} after the relay packet
37672
+ * lands on the hub. Public so callers who created the intent via
37673
+ * {@link LeverageYieldService.createVaultIntent} and relayed it themselves can finish the
37674
+ * flow manually.
37675
+ *
37676
+ * @param request - `{ intent_tx_hash }` — the hub-chain (Sonic) tx hash where the intent
37677
+ * was registered (the relay packet's `dst_tx_hash`, or the spoke tx hash for hub-sourced
37678
+ * intents).
37679
+ */
37680
+ async notifySolver(request) {
37681
+ try {
37682
+ const result = await SolverApiService.postExecution(request, this.config.solver, this.config.logger);
37683
+ if (result.ok) return result;
37684
+ const detail = result.error?.detail ?? {
37685
+ code: -999,
37686
+ // SolverIntentErrorCode.UNKNOWN
37687
+ message: "Solver returned malformed error response"
37688
+ };
37689
+ return {
37690
+ ok: false,
37691
+ error: new SodaxError("EXTERNAL_API_ERROR", detail.message, {
37692
+ feature: "leverageYield",
37693
+ context: {
37694
+ phase: "postExecution",
37695
+ api: "solver",
37696
+ solverCode: detail.code,
37697
+ solverDetail: detail
37698
+ }
37699
+ })
37700
+ };
37701
+ } catch (error) {
37702
+ if (isLeverageYieldPostExecutionError(error)) return { ok: false, error };
37703
+ return { ok: false, error: executionFailed("leverageYield", error, { phase: "postExecution" }) };
37704
+ }
37705
+ }
37706
+ /**
37707
+ * Approves the vault's underlying asset to the leverage vault on Sonic. For callers
37708
+ * interacting with the vault directly on the hub — the swap-style {@link
37709
+ * LeverageYieldService.deposit} flow handles its own approvals.
37710
+ */
37711
+ async approve(params) {
37712
+ const baseCtx = { action: "approve" };
37713
+ try {
37714
+ leverageYieldInvariant(params.amount > 0n, "Amount must be greater than 0", { ...baseCtx, field: "amount" });
37715
+ leverageYieldInvariant(params.vault.length > 0, "Vault address is required", { ...baseCtx, field: "vault" });
37716
+ const assetResult = await this.getAsset(params.vault);
37717
+ if (!assetResult.ok) {
37718
+ return { ok: false, error: approveFailed("leverageYield", assetResult.error, baseCtx) };
37719
+ }
37720
+ const from = await params.walletProvider.getWalletAddress();
37721
+ const baseApprove = {
37722
+ token: assetResult.value,
37723
+ amount: params.amount,
37724
+ from,
37725
+ spender: params.vault
37726
+ };
37727
+ if (params.raw) {
37728
+ const tx2 = await Erc20Service.approve({ ...baseApprove, raw: true });
37729
+ return { ok: true, value: tx2 };
37730
+ }
37731
+ const tx = await Erc20Service.approve({
37732
+ ...baseApprove,
37733
+ raw: false,
37734
+ walletProvider: params.walletProvider
37735
+ });
37736
+ return { ok: true, value: tx };
37737
+ } catch (error) {
37738
+ if (isLeverageYieldApproveError(error)) return { ok: false, error };
37739
+ return { ok: false, error: approveFailed("leverageYield", error, baseCtx) };
37740
+ }
37741
+ }
37742
+ /**
37743
+ * Reads on-chain allowance of the vault's underlying asset for `owner → vault`. Returns
37744
+ * `true` when the allowance covers `amount`. Use before a direct
37745
+ * {@link LeverageYieldService.deposit}.
37746
+ */
37747
+ async isAllowanceValid(params) {
37748
+ const baseCtx = { action: "allowanceCheck" };
37749
+ try {
37750
+ leverageYieldInvariant(params.amount > 0n, "Amount must be greater than 0", { ...baseCtx, field: "amount" });
37751
+ const assetResult = await this.getAsset(params.vault);
37752
+ if (!assetResult.ok) {
37753
+ return { ok: false, error: allowanceCheckFailed("leverageYield", assetResult.error, baseCtx) };
37754
+ }
37755
+ const allowance = await this.hubProvider.publicClient.readContract({
37756
+ address: assetResult.value,
37757
+ abi: erc20Abi$1,
37758
+ functionName: "allowance",
37759
+ args: [params.owner, params.vault]
37760
+ });
37761
+ return { ok: true, value: allowance >= params.amount };
37762
+ } catch (error) {
37763
+ if (isLeverageYieldAllowanceCheckError(error)) return { ok: false, error };
37764
+ return { ok: false, error: allowanceCheckFailed("leverageYield", error, baseCtx) };
37765
+ }
37766
+ }
37767
+ // ─── Reads ──────────────────────────────────────────────────────────────
37768
+ /** ERC-4626 `asset()` of the vault — the sodaWEETH-style underlying. */
37769
+ async getAsset(vault) {
37770
+ try {
37771
+ const value = await this.hubProvider.publicClient.readContract({
37772
+ address: vault,
37773
+ abi: leverageYieldVaultAbi,
37774
+ functionName: "asset"
37775
+ });
37776
+ return { ok: true, value };
37777
+ } catch (error) {
37778
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
37779
+ return { ok: false, error: lookupFailed("leverageYield", "getAsset", error) };
37780
+ }
37781
+ }
37782
+ /** Reads the vault's leveraged position snapshot via the non-standard `getPositionDetails`. */
37783
+ async getPosition(vault) {
37784
+ try {
37785
+ const [collateral, debt, ltv, healthFactor, idleAsset] = await this.hubProvider.publicClient.readContract({
37786
+ address: vault,
37787
+ abi: leverageYieldVaultAbi,
37788
+ functionName: "getPositionDetails"
37789
+ });
37790
+ return { ok: true, value: { collateral, debt, ltv, healthFactor, idleAsset } };
37791
+ } catch (error) {
37792
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
37793
+ return { ok: false, error: lookupFailed("leverageYield", "getPosition", error) };
37794
+ }
37795
+ }
37796
+ /**
37797
+ * Computes the steady-state APR of a leverage-yield vault from the AAVE supply/borrow
37798
+ * rates of its asset and borrowToken, scaled by the vault's target leverage. Matches the
37799
+ * convention used by leveraged-LSD vaults (Origami, Gearbox, etc.) — assumes constant
37800
+ * LTV at `targetLTV` and constant AAVE rates.
37801
+ *
37802
+ * Returns raw fields in RAY (1e27, AAVE's native rate scale) plus the leverage multiplier
37803
+ * in WAD (1e18). See {@link LeverageYieldApr} for the formula and caveats.
37804
+ */
37805
+ async getApr(vault) {
37806
+ try {
37807
+ const [pool, asset, borrowToken, targetLtvBps] = await Promise.all([
37808
+ this.hubProvider.publicClient.readContract({
37809
+ address: vault,
37810
+ abi: leverageYieldVaultAbi,
37811
+ functionName: "pool"
37812
+ }),
37813
+ this.hubProvider.publicClient.readContract({
37814
+ address: vault,
37815
+ abi: leverageYieldVaultAbi,
37816
+ functionName: "asset"
37817
+ }),
37818
+ this.hubProvider.publicClient.readContract({
37819
+ address: vault,
37820
+ abi: leverageYieldVaultAbi,
37821
+ functionName: "borrowToken"
37822
+ }),
37823
+ this.hubProvider.publicClient.readContract({
37824
+ address: vault,
37825
+ abi: leverageYieldVaultAbi,
37826
+ functionName: "targetLTV"
37827
+ })
37828
+ ]);
37829
+ const [assetReserve, borrowReserve] = await Promise.all([
37830
+ this.hubProvider.publicClient.readContract({
37831
+ address: pool,
37832
+ abi: poolAbi,
37833
+ functionName: "getReserveData",
37834
+ args: [asset]
37835
+ }),
37836
+ this.hubProvider.publicClient.readContract({
37837
+ address: pool,
37838
+ abi: poolAbi,
37839
+ functionName: "getReserveData",
37840
+ args: [borrowToken]
37841
+ })
37842
+ ]);
37843
+ const supplyAprRay = assetReserve.currentLiquidityRate;
37844
+ const borrowAprRay = borrowReserve.currentVariableBorrowRate;
37845
+ const BPS = 10000n;
37846
+ const WAD2 = 1000000000000000000n;
37847
+ leverageYieldInvariant(targetLtvBps < BPS, `targetLTV (${targetLtvBps}) must be < 100% (10_000 bps)`, {
37848
+ method: "getApr",
37849
+ field: "targetLtvBps"
37850
+ });
37851
+ const leverageMultiplierWad = targetLtvBps * WAD2 / (BPS - targetLtvBps);
37852
+ const spreadRay = supplyAprRay - borrowAprRay;
37853
+ const netAprRay = supplyAprRay + spreadRay * leverageMultiplierWad / WAD2;
37854
+ return {
37855
+ ok: true,
37856
+ value: { supplyAprRay, borrowAprRay, targetLtvBps, leverageMultiplierWad, netAprRay }
37857
+ };
37858
+ } catch (error) {
37859
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
37860
+ return { ok: false, error: lookupFailed("leverageYield", "getApr", error) };
37861
+ }
37862
+ }
37863
+ /**
37864
+ * Off-chain LSD staking-APR for the vault's underlying asset. Looks the vault up in the
37865
+ * registry, hits DefiLlama's per-pool chart endpoint for the configured `poolId`, and on
37866
+ * any fetch failure returns the registry's hardcoded `fallbackAprPct` with `stale: true`.
37867
+ *
37868
+ * Always resolves to `{ ok: true, ... }` for a known vault — the fallback path replaces
37869
+ * the error, since a missing LSD APR shouldn't break the parent call. Returns
37870
+ * `{ aprRay: 0n, stale: true, label: 'no LSD source' }` for vaults without an
37871
+ * `lsdSource` configured (non-LSD strategies); callers can treat that as "skip LSD".
37872
+ */
37873
+ async getLsdApr(vault) {
37874
+ try {
37875
+ const cfg = this.getVaultByAddress(vault);
37876
+ const source = cfg?.lsdSource;
37877
+ if (!source) {
37878
+ return { ok: true, value: { aprRay: 0n, label: "no LSD source", stale: true } };
37879
+ }
37880
+ try {
37881
+ const aprPct = await fetchDefillamaApr(source.poolId);
37882
+ return { ok: true, value: { aprRay: pctToRay(aprPct), label: source.label, stale: false } };
37883
+ } catch (fetchError) {
37884
+ this.config.logger.warn("[leverageYield] DefiLlama APR fetch failed; using fallbackAprPct", {
37885
+ vault,
37886
+ poolId: source.poolId,
37887
+ fallbackAprPct: source.fallbackAprPct,
37888
+ error: fetchError instanceof Error ? fetchError.message : String(fetchError)
37889
+ });
37890
+ return {
37891
+ ok: true,
37892
+ value: { aprRay: pctToRay(source.fallbackAprPct), label: `${source.label} (fallback)`, stale: true }
37893
+ };
37894
+ }
37895
+ } catch (error) {
37896
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
37897
+ return { ok: false, error: lookupFailed("leverageYield", "getLsdApr", error) };
37898
+ }
37899
+ }
37900
+ /**
37901
+ * Combined view of {@link getApr} + {@link getLsdApr}: re-applies the vault's leverage
37902
+ * formula with the LSD's native staking yield folded into the supply side, exposing the
37903
+ * **effective** net APR that LSD-backed strategies actually earn. The AAVE-only
37904
+ * `netAprRay` is preserved on the return value for callers who want to display both.
37905
+ *
37906
+ * effectiveSupply = supplyAprRay + lsdApr.aprRay
37907
+ * effectiveNet = effectiveSupply + leverage × (effectiveSupply − borrowAprRay)
37908
+ *
37909
+ * Fetches AAVE rates and the LSD APR in parallel for one round-trip's worth of latency.
37910
+ */
37911
+ async getEffectiveApr(vault) {
37912
+ try {
37913
+ const [aprResult, lsdResult] = await Promise.all([this.getApr(vault), this.getLsdApr(vault)]);
37914
+ if (!aprResult.ok) return aprResult;
37915
+ if (!lsdResult.ok) return lsdResult;
37916
+ const apr = aprResult.value;
37917
+ const lsd = lsdResult.value;
37918
+ const effectiveSupplyAprRay = apr.supplyAprRay + lsd.aprRay;
37919
+ const spreadRay = effectiveSupplyAprRay - apr.borrowAprRay;
37920
+ const WAD2 = 1000000000000000000n;
37921
+ const effectiveNetAprRay = effectiveSupplyAprRay + spreadRay * apr.leverageMultiplierWad / WAD2;
37922
+ return {
37923
+ ok: true,
37924
+ value: { ...apr, lsdApr: lsd, effectiveSupplyAprRay, effectiveNetAprRay }
37925
+ };
37926
+ } catch (error) {
37927
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
37928
+ return { ok: false, error: lookupFailed("leverageYield", "getEffectiveApr", error) };
37929
+ }
37930
+ }
37931
+ /** Synchronously withdrawable assets for `owner` (clamped against leverage HF floor). */
37932
+ async getMaxWithdraw(vault, owner) {
37933
+ const inner = await Erc4626Service.getMaxWithdraw(vault, owner, this.hubProvider.publicClient);
37934
+ if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "getMaxWithdraw", inner.error) };
37935
+ return { ok: true, value: inner.value };
37936
+ }
37937
+ /** Total underlying assets currently held by the vault (vault-asset units, 18 decimals) — TVL. */
37938
+ async getTotalAssets(vault) {
37939
+ const inner = await Erc4626Service.getTotalAssets(vault, this.hubProvider.publicClient);
37940
+ if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "getTotalAssets", inner.error) };
37941
+ return { ok: true, value: inner.value };
37942
+ }
37943
+ /** Shares minted for a given asset deposit. */
37944
+ async previewDeposit(vault, assets) {
37945
+ const inner = await Erc4626Service.previewDeposit(vault, assets, this.hubProvider.publicClient);
37946
+ if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "previewDeposit", inner.error) };
37947
+ return { ok: true, value: inner.value };
37948
+ }
37949
+ /** Shares burned for a given asset withdrawal. */
37950
+ async previewWithdraw(vault, assets) {
37951
+ const inner = await Erc4626Service.previewWithdraw(vault, assets, this.hubProvider.publicClient);
37952
+ if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "previewWithdraw", inner.error) };
37953
+ return { ok: true, value: inner.value };
37954
+ }
37955
+ /** Assets received for a given share redemption. */
37956
+ async previewRedeem(vault, shares) {
37957
+ const inner = await Erc4626Service.previewRedeem(vault, shares, this.hubProvider.publicClient);
37958
+ if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "previewRedeem", inner.error) };
37959
+ return { ok: true, value: inner.value };
37960
+ }
37961
+ /** Vault shares held by `owner`. */
37962
+ async getShareBalance(vault, owner) {
37963
+ try {
37964
+ const value = await this.hubProvider.publicClient.readContract({
37965
+ address: vault,
37966
+ abi: erc20Abi$1,
37967
+ functionName: "balanceOf",
37968
+ args: [owner]
37969
+ });
37970
+ return { ok: true, value };
37971
+ } catch (error) {
37972
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
37973
+ return { ok: false, error: lookupFailed("leverageYield", "getShareBalance", error) };
37974
+ }
37975
+ }
37976
+ /**
37977
+ * Convenience: resolves the user's hub wallet from `(srcChainKey, srcAddress)` and
37978
+ * returns its on-chain `maxWithdraw`, less {@link MAX_WITHDRAW_DUST_BUFFER}. The trim
37979
+ * keeps the value safe for an asset-denominated ERC-4626 `withdraw` — the raw
37980
+ * `maxWithdraw` can trip the round-up that asks for one more share than the user holds.
37981
+ */
37982
+ async getMaxWithdrawForUser(vault, srcChainKey, srcAddress) {
37983
+ try {
37984
+ const hubWallet = await this.hubProvider.getUserHubWalletAddress(srcAddress, srcChainKey);
37985
+ const maxWithdrawResult = await this.getMaxWithdraw(vault, hubWallet);
37986
+ if (!maxWithdrawResult.ok) return maxWithdrawResult;
37987
+ const buffered = maxWithdrawResult.value > MAX_WITHDRAW_DUST_BUFFER ? maxWithdrawResult.value - MAX_WITHDRAW_DUST_BUFFER : 0n;
37988
+ return { ok: true, value: buffered };
37989
+ } catch (error) {
37990
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
37991
+ return { ok: false, error: lookupFailed("leverageYield", "getMaxWithdrawForUser", error, { srcChainKey }) };
37992
+ }
37993
+ }
37994
+ /**
37995
+ * Convenience: resolves the user's hub wallet from `(srcChainKey, srcAddress)` and
37996
+ * returns its on-chain share balance.
37997
+ */
37998
+ async getShareBalanceForUser(vault, srcChainKey, srcAddress) {
37999
+ try {
38000
+ const hubWallet = await this.hubProvider.getUserHubWalletAddress(srcAddress, srcChainKey);
38001
+ return await this.getShareBalance(vault, hubWallet);
38002
+ } catch (error) {
38003
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
38004
+ return { ok: false, error: lookupFailed("leverageYield", "getShareBalanceForUser", error, { srcChainKey }) };
38005
+ }
38006
+ }
38007
+ };
38008
+
37090
38009
  // src/shared/entities/Sodax.ts
37091
38010
  var Sodax = class {
37092
38011
  instanceConfig;
@@ -37108,6 +38027,8 @@ var Sodax = class {
37108
38027
  // Recovery service for withdrawing stuck hub-wallet assets back to a spoke chain
37109
38028
  dex;
37110
38029
  // Dex service enabling DEX operations
38030
+ leverageYield;
38031
+ // Leverage-yield service: cross-chain deposits / withdrawals into ERC-4626 leverage vaults on Sonic
37111
38032
  config;
37112
38033
  // Config service enabling configuration data fetching from the backend API or fallbacking to default values
37113
38034
  hubProvider;
@@ -37153,6 +38074,11 @@ var Sodax = class {
37153
38074
  config: this.config,
37154
38075
  spoke: this.spoke
37155
38076
  });
38077
+ this.leverageYield = new LeverageYieldService({
38078
+ hubProvider: this.hubProvider,
38079
+ config: this.config,
38080
+ spoke: this.spoke
38081
+ });
37156
38082
  }
37157
38083
  /**
37158
38084
  * Initializes the Sodax instance with dynamic configuration.
@@ -37193,4 +38119,4 @@ var isPartnerError = isCodeMember(PARTNER_CODES);
37193
38119
  (*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
37194
38120
  */
37195
38121
 
37196
- export { ALLOWANCE_CHECK_CODES, APPROVE_CODES, AssetService, BITCOIN_CHAIN_KEYS, BITCOIN_CHAIN_KEYS_SET, BTC_WALLET_ADDRESS_TYPES, BackendApiService, BalnSwapService, BigIntToHex, BigNumberZeroDecimal, BitcoinSpokeService, BnUSDMigrationService, BridgeService, CHAIN_KEYS, CONFIG_VERSION, CREATE_INTENT_CODES, ChainKeys, ChainTypeArr, ClService, ConfigService, CustomSorobanServer, CustomStellarAccount, DEFAULT_BACKEND_API_ENDPOINT, DEFAULT_BACKEND_API_HEADERS, DEFAULT_BACKEND_API_TIMEOUT, DEFAULT_DEADLINE_OFFSET, DEFAULT_MAX_RETRY, DEFAULT_RELAYER_API_ENDPOINT, DEFAULT_RELAY_TX_TIMEOUT, DEFAULT_RETRY_DELAY_MS, DexService, EVM_CHAIN_ID_TO_KEY, EVM_CHAIN_KEYS, EVM_CHAIN_KEYS_SET, EVM_SPOKE_ONLY_CHAIN_KEYS, EVM_SPOKE_ONLY_CHAIN_KEYS_SET, Erc20Service, Erc4626Service, EvmAssetManagerService, EvmHubProvider, EvmSolverService, EvmSpokeService, EvmVaultTokenService, FEE_PERCENTAGE_SCALE, GAS_ESTIMATION_CODES, HALF_RAY, HALF_WAD, HUB_CHAIN_KEY, HttpRelayError, HubVaultSymbols, ICON_CHAIN_KEYS, ICON_CHAIN_KEYS_SET, ICON_TX_RESULT_WAIT_MAX_RETRY, INJECTIVE_CHAIN_KEYS, INJECTIVE_CHAIN_KEYS_SET, INTENT_CHAIN_IDS, IconSpokeService, IcxMigrationService, Injective20Token, InjectiveSpokeService, IntentCreatedEventAbi, IntentDataType, IntentFilledEventAbi, IntentRelayChainIdToChainKey, IntentsAbi, LOOKUP_CODES, LTV_PRECISION, LendingPoolService, LockupMultiplier, LockupPeriod, MAX_UINT256, MigrationService, MintPositionEventAbi, MoneyMarketDataService, MoneyMarketService, NEAR_CHAIN_KEYS, NEAR_CHAIN_KEYS_SET, NEAR_DEFAULT_GAS, NEAR_STORAGE_DEPOSIT, NearSpokeService, PartnerFeeClaimService, PartnerService, Permit2Service, ProtocolIntentsAbi, RAY, RAY_DECIMALS, RELAY_ERROR_CODES, RadfiApiError, RadfiProvider, RecoveryService, RelayChainIdMap, SECONDS_PER_YEAR, SODAX_ERROR_CODES, SODAX_FEATURES, SOLANA_CHAIN_KEYS, SOLANA_CHAIN_KEYS_SET, SONIC_CHAIN_KEYS, SONIC_CHAIN_KEYS_SET, STACKS_CHAIN_KEYS, STACKS_CHAIN_KEYS_SET, STELLAR_CHAIN_KEYS, STELLAR_CHAIN_KEYS_SET, SUI_CHAIN_KEYS, SUI_CHAIN_KEYS_SET, SodaTokens, Sodax, SodaxError, SolanaSpokeService, SolverApiService, SolverIntentErrorCode, SolverIntentStatusCode, SonicSpokeService, SpokeService, StacksSpokeService, StakingLogic, StakingService, StatATokenAddresses, StellarSpokeService, SuiSpokeService, SupportedMigrationTokens, SwapService, USD_DECIMALS, UiPoolDataProviderService, VAULT_TOKEN_DECIMALS, WAD, WAD_RAY_RATIO, WEI_DECIMALS, adjustAmountByFee, allowanceCheckFailed, apiConfig, approveFailed, arbitrumSupportedTokens, assetManagerAbi, avalancheSupportedTokens, balnSwapAbi, baseChainInfo, baseSupportedTokens, binomialApproximatedRayPow, bitcoinSupportedTokens, bnUSDLegacySpokeChainIds, bnUSDLegacyTokens, bridgeConfig, bridgeInvariant, bscSupportedTokens, calcOpReturnOutputVbytes, calculateAllReserveIncentives, calculateAllUserIncentives, calculateAvailableBorrowsMarketReferenceCurrency, calculateCompoundedInterest, calculateCompoundedRate, calculateFeeAmount, calculateHealthFactorFromBalances, calculateHealthFactorFromBalancesBigUnits, calculateLinearInterest, calculatePercentageFeeAmount, clPoolAbi, clPoolManagerAbi, clPositionManagerAbi, clQuoterAbi, clRouterAbi, clTickLensAbi, concentratedLiquidityConfig, connectionAbi, consoleLogger, convertTransactionInstructionToRaw, createInvariant, deepMerge, defaultHookAbi, detectBitcoinAddressType, dexConfig, dexInvariant, dexPools, encodeAddress, encodeBtcPayloadToBytes, encodeContractCalls, erc20Abi, erc4626Abi, estimateBitcoinTxSize, ethereumSupportedTokens, executionFailed, formatBasisPoints, formatEModeCategory, formatEModes, formatPercentage, formatReserve, formatReserveUSD, formatReserves, formatReservesAndIncentives, formatUserSummary, formatUserSummaryAndIncentives, gasEstimationFailed, getAllLegacybnUSDTokens, getAndFormatReserveEModes, getAssetManagerIdl, getAssetManagerProgram, getChainKeyFromRelayChainId, getChainType, getCompoundedBalance, getConcentratedLiquidityConfig, getConnectionIdl, getConnectionProgram, getEvmChainKeyByChainId, getEvmViemChain, getIconAddressBytes, getIntentRelayChainId, getLinearBalance, getMarketReferenceCurrencyAndUsdBalance, getPacket, getProvider, getRandomBytes, getReserveNormalizedIncome, getReservesEModes, getSolanaAddressBytes, getSolverConfig, getSupportedSolverTokens, getTransactionPackets, getbnUSDToken, hexToBigInt, hexToSolanaAddress, hubConfig, hyper, hyperevmSupportedTokens, iconSupportedTokens, injectiveSupportedTokens, intentCreationFailed, isBalnMigrateParams, isBitcoinChainKey, isBitcoinChainKeyType, isBitcoinWalletProviderType, isBridgeAllowanceCheckError, isBridgeApproveError, isBridgeCreateIntentError, isBridgeError, isBridgeLookupError, isBridgeOrchestrationError, isCodeMember, isDexError, isEvmChainKey, isEvmChainKeyType, isEvmSpokeChainConfig, isEvmSpokeOnlyChainKey, isEvmSpokeOnlyChainKeyType, isEvmWalletProviderType, isFeatureError, isHubChainKey, isHubChainKeyType, isIconAddress, isIconChainKey, isIconChainKeyType, isIcxCreateRevertMigrationParams, isIcxMigrateParams, isInjectiveChainKey, isInjectiveChainKeyType, isJsonRpcPayloadResponse, isLegacybnUSDChainId, isLegacybnUSDToken, isMigrateOrchestrationError, isMigrationAllowanceCheckError, isMigrationApproveError, isMigrationCreateIntentError, isMigrationError, isMigrationLookupError, isMoneyMarketAllowanceCheckError, isMoneyMarketApproveError, isMoneyMarketCreateIntentError, isMoneyMarketError, isMoneyMarketGasEstimationError, isMoneyMarketOrchestrationError, isNativeToken, isNearChainKey, isNearChainKeyType, isNewbnUSDChainId, isNewbnUSDToken, isOptionalBitcoinWalletProviderType, isOptionalEvmWalletProviderType, isOptionalStellarWalletProviderType, isPartnerError, isPartnerFeeAmount, isPartnerFeePercentage, isPostExecutionError, isRawDestinationParams, isRecoveryError, isResponseAddressType, isResponseSigningType, isRevertMigrationOrchestrationError, isSodaxError, isSolanaChainKey, isSolanaChainKeyType, isSolanaNativeToken, isSonicChainKey, isSonicChainKeyType, isSpokeApproveParamsEvmSpoke, isSpokeApproveParamsHub, isSpokeApproveParamsStellar, isSpokeChainKey, isSpokeIsAllowanceValidParamsEvmSpoke, isSpokeIsAllowanceValidParamsHub, isSpokeIsAllowanceValidParamsStellar, isStacksChainKey, isStacksChainKeyType, isStakeOrchestrationError, isStakingAllowanceCheckError, isStakingApproveError, isStakingCreateIntentError, isStakingError, isStakingInfoFetchError, isStakingOrchestrationError, isStellarChainKey, isStellarChainKeyType, isStellarWalletProviderType, isSubmitSwapTxResponse, isSubmitSwapTxStatusResponse, isSuiChainKey, isSuiChainKeyType, isSupportedBitcoinAddressType, isSwapCreateIntentError, isSwapError, isSwapSupportedToken, isUndefinedOrValidWalletProviderForChainKey, isUnifiedBnUSDMigrateParams, isValidWalletProviderForChainKey, kaiaSupportedTokens, lightlinkSupportedTokens, lookupFailed, mapRelayFailure, mergeSodaxConfig, messageOf, migrationInvariant, mintPositionParamsAbi, mmInvariant, modifyLiquidityParamsAbi, moneyMarketConfig, moneyMarketReserveAssets, moneyMarketSupportedTokens, nativeToUSD, nearSupportedTokens, newbnUSDSpokeChainIds, normalize, normalizeBN, normalizePsbtToBase64, normalizeSignatureToBase64, normalizedToUsd, optimismSupportedTokens, pancakeSwapInfinityDefaultHookAbi, pancakeSwapInfinityPoolManagerAbi, pancakeSwapInfinityPositionManagerAbi, parseToStroops, parseTokenArrayFromJson, partnerInvariant, permit2Abi, polygonSupportedTokens, poolAbi, poolKeyAbi, randomUint256, rayDiv, rayMul, rayPow, rayToWad, recoveryInvariant, redbellySupportedTokens, relayConfig, relayTxAndWaitPacket, requestAddress, requestJsonRpc, requestSigning, resolveLogger, retry, reverseEncodeAddress, serializeAddressData, silentLogger, sleep, sodaxConfig, sodaxInvariant, solanaSupportedTokens, solverConfig, sonicSupportedTokens, sonicWalletFactoryAbi, spokeAssetManagerAbi, spokeChainConfig, spokeChainKeysSet, stacksSupportedTokens, stakedSodaAbi, stakingInvariant, stakingRouterAbi, stataTokenFactoryAbi, stellarSupportedTokens, submitTransaction, suiSupportedTokens, supportedSpokeChains, supportedTokensByChain, swapExactInSingleParamsAbi, swapInvariant, swapSupportedTokens, swapsConfig, uiPoolDataAbi, universalRouterAbi, unknownFailed, usesBip322MessageSigning, valueToBigNumber, valueToZDBigNumber, variableDebtTokenAbi, vaultTokenAbi, verifyFailed, wadToRay, waitForStacksTransaction, waitForTransactionReceipt, waitUntilIntentExecuted, walletFactoryAbi, wrappedSonicAbi };
38122
+ export { ALLOWANCE_CHECK_CODES, APPROVE_CODES, AssetService, BITCOIN_CHAIN_KEYS, BITCOIN_CHAIN_KEYS_SET, BTC_WALLET_ADDRESS_TYPES, BackendApiService, BalnSwapService, BigIntToHex, BigNumberZeroDecimal, BitcoinSpokeService, BnUSDMigrationService, BridgeService, CHAIN_KEYS, CONFIG_VERSION, CREATE_INTENT_CODES, ChainKeys, ChainTypeArr, ClService, ConfigService, CustomSorobanServer, CustomStellarAccount, DEFAULT_BACKEND_API_ENDPOINT, DEFAULT_BACKEND_API_HEADERS, DEFAULT_BACKEND_API_TIMEOUT, DEFAULT_DEADLINE_OFFSET, DEFAULT_MAX_RETRY, DEFAULT_RELAYER_API_ENDPOINT, DEFAULT_RELAY_TX_TIMEOUT, DEFAULT_RETRY_DELAY_MS, DexService, EVM_CHAIN_ID_TO_KEY, EVM_CHAIN_KEYS, EVM_CHAIN_KEYS_SET, EVM_SPOKE_ONLY_CHAIN_KEYS, EVM_SPOKE_ONLY_CHAIN_KEYS_SET, Erc20Service, Erc4626Service, EvmAssetManagerService, EvmHubProvider, EvmSolverService, EvmSpokeService, EvmVaultTokenService, FEE_PERCENTAGE_SCALE, GAS_ESTIMATION_CODES, HALF_RAY, HALF_WAD, HUB_CHAIN_KEY, HttpRelayError, HubVaultSymbols, ICON_CHAIN_KEYS, ICON_CHAIN_KEYS_SET, ICON_TX_RESULT_WAIT_MAX_RETRY, INJECTIVE_CHAIN_KEYS, INJECTIVE_CHAIN_KEYS_SET, INTENT_CHAIN_IDS, IconSpokeService, IcxMigrationService, Injective20Token, InjectiveSpokeService, IntentCreatedEventAbi, IntentDataType, IntentFilledEventAbi, IntentRelayChainIdToChainKey, IntentsAbi, LOOKUP_CODES, LTV_PRECISION, LendingPoolService, LeverageYieldService, LockupMultiplier, LockupPeriod, LsodaSymbols, LsodaTokens, MAX_UINT256, MigrationService, MintPositionEventAbi, MoneyMarketDataService, MoneyMarketService, NEAR_CHAIN_KEYS, NEAR_CHAIN_KEYS_SET, NEAR_DEFAULT_GAS, NEAR_STORAGE_DEPOSIT, NearSpokeService, PartnerFeeClaimService, PartnerService, Permit2Service, ProtocolIntentsAbi, RAY, RAY_DECIMALS, RELAY_ERROR_CODES, RadfiApiError, RadfiProvider, RecoveryService, RelayChainIdMap, SECONDS_PER_YEAR, SODAX_ERROR_CODES, SODAX_FEATURES, SOLANA_CHAIN_KEYS, SOLANA_CHAIN_KEYS_SET, SONIC_CHAIN_KEYS, SONIC_CHAIN_KEYS_SET, STACKS_CHAIN_KEYS, STACKS_CHAIN_KEYS_SET, STELLAR_CHAIN_KEYS, STELLAR_CHAIN_KEYS_SET, SUI_CHAIN_KEYS, SUI_CHAIN_KEYS_SET, SodaTokens, Sodax, SodaxError, SolanaSpokeService, SolverApiService, SolverIntentErrorCode, SolverIntentStatusCode, SonicSpokeService, SpokeService, StacksSpokeService, StakingLogic, StakingService, StatATokenAddresses, StellarSpokeService, SuiSpokeService, SupportedMigrationTokens, SwapService, USD_DECIMALS, UiPoolDataProviderService, VAULT_TOKEN_DECIMALS, WAD, WAD_RAY_RATIO, WEI_DECIMALS, adjustAmountByFee, allowanceCheckFailed, apiConfig, approveFailed, arbitrumSupportedTokens, assetManagerAbi, avalancheSupportedTokens, balnSwapAbi, baseChainInfo, baseSupportedTokens, binomialApproximatedRayPow, bitcoinSupportedTokens, bnUSDLegacySpokeChainIds, bnUSDLegacyTokens, bridgeConfig, bridgeInvariant, bscSupportedTokens, calcOpReturnOutputVbytes, calculateAllReserveIncentives, calculateAllUserIncentives, calculateAvailableBorrowsMarketReferenceCurrency, calculateCompoundedInterest, calculateCompoundedRate, calculateFeeAmount, calculateHealthFactorFromBalances, calculateHealthFactorFromBalancesBigUnits, calculateLinearInterest, calculatePercentageFeeAmount, clPoolAbi, clPoolManagerAbi, clPositionManagerAbi, clQuoterAbi, clRouterAbi, clTickLensAbi, concentratedLiquidityConfig, connectionAbi, consoleLogger, convertTransactionInstructionToRaw, createInvariant, deepMerge, defaultHookAbi, detectBitcoinAddressType, dexConfig, dexInvariant, dexPools, encodeAddress, encodeBtcPayloadToBytes, encodeContractCalls, erc20Abi, erc4626Abi, estimateBitcoinTxSize, ethereumSupportedTokens, executionFailed, formatBasisPoints, formatEModeCategory, formatEModes, formatPercentage, formatReserve, formatReserveUSD, formatReserves, formatReservesAndIncentives, formatUserSummary, formatUserSummaryAndIncentives, gasEstimationFailed, getAllLegacybnUSDTokens, getAndFormatReserveEModes, getAssetManagerIdl, getAssetManagerProgram, getChainKeyFromRelayChainId, getChainType, getCompoundedBalance, getConcentratedLiquidityConfig, getConnectionIdl, getConnectionProgram, getEvmChainKeyByChainId, getEvmViemChain, getIconAddressBytes, getIntentRelayChainId, getLinearBalance, getMarketReferenceCurrencyAndUsdBalance, getPacket, getProvider, getRandomBytes, getReserveNormalizedIncome, getReservesEModes, getSolanaAddressBytes, getSolverConfig, getSupportedSolverTokens, getTransactionPackets, getbnUSDToken, hexToBigInt, hexToSolanaAddress, hubConfig, hyper, hyperevmSupportedTokens, iconSupportedTokens, injectiveSupportedTokens, intentCreationFailed, isBalnMigrateParams, isBitcoinChainKey, isBitcoinChainKeyType, isBitcoinWalletProviderType, isBridgeAllowanceCheckError, isBridgeApproveError, isBridgeCreateIntentError, isBridgeError, isBridgeLookupError, isBridgeOrchestrationError, isCodeMember, isDexError, isEvmChainKey, isEvmChainKeyType, isEvmSpokeChainConfig, isEvmSpokeOnlyChainKey, isEvmSpokeOnlyChainKeyType, isEvmWalletProviderType, isFeatureError, isHubChainKey, isHubChainKeyType, isIconAddress, isIconChainKey, isIconChainKeyType, isIcxCreateRevertMigrationParams, isIcxMigrateParams, isInjectiveChainKey, isInjectiveChainKeyType, isJsonRpcPayloadResponse, isLegacybnUSDChainId, isLegacybnUSDToken, isLeverageYieldAllowanceCheckError, isLeverageYieldApproveError, isLeverageYieldCreateIntentError, isLeverageYieldError, isLeverageYieldLookupError, isLeverageYieldPostExecutionError, isLeverageYieldSwapError, isMigrateOrchestrationError, isMigrationAllowanceCheckError, isMigrationApproveError, isMigrationCreateIntentError, isMigrationError, isMigrationLookupError, isMoneyMarketAllowanceCheckError, isMoneyMarketApproveError, isMoneyMarketCreateIntentError, isMoneyMarketError, isMoneyMarketGasEstimationError, isMoneyMarketOrchestrationError, isNativeToken, isNearChainKey, isNearChainKeyType, isNewbnUSDChainId, isNewbnUSDToken, isOptionalBitcoinWalletProviderType, isOptionalEvmWalletProviderType, isOptionalStellarWalletProviderType, isPartnerError, isPartnerFeeAmount, isPartnerFeePercentage, isPostExecutionError, isRawDestinationParams, isRecoveryError, isResponseAddressType, isResponseSigningType, isRevertMigrationOrchestrationError, isSodaxError, isSolanaChainKey, isSolanaChainKeyType, isSolanaNativeToken, isSonicChainKey, isSonicChainKeyType, isSpokeApproveParamsEvmSpoke, isSpokeApproveParamsHub, isSpokeApproveParamsStellar, isSpokeChainKey, isSpokeIsAllowanceValidParamsEvmSpoke, isSpokeIsAllowanceValidParamsHub, isSpokeIsAllowanceValidParamsStellar, isStacksChainKey, isStacksChainKeyType, isStakeOrchestrationError, isStakingAllowanceCheckError, isStakingApproveError, isStakingCreateIntentError, isStakingError, isStakingInfoFetchError, isStakingOrchestrationError, isStellarChainKey, isStellarChainKeyType, isStellarWalletProviderType, isSubmitSwapTxResponse, isSubmitSwapTxStatusResponse, isSuiChainKey, isSuiChainKeyType, isSupportedBitcoinAddressType, isSwapCreateIntentError, isSwapError, isSwapSupportedToken, isUndefinedOrValidWalletProviderForChainKey, isUnifiedBnUSDMigrateParams, isValidWalletProviderForChainKey, kaiaSupportedTokens, leverageYieldConfig, leverageYieldInvariant, leverageYieldVaults, lightlinkSupportedTokens, lookupFailed, mapRelayFailure, mergeSodaxConfig, messageOf, migrationInvariant, mintPositionParamsAbi, mmInvariant, modifyLiquidityParamsAbi, moneyMarketConfig, moneyMarketReserveAssets, moneyMarketSupportedTokens, nativeToUSD, nearSupportedTokens, newbnUSDSpokeChainIds, normalize, normalizeBN, normalizePsbtToBase64, normalizeSignatureToBase64, normalizedToUsd, optimismSupportedTokens, pancakeSwapInfinityDefaultHookAbi, pancakeSwapInfinityPoolManagerAbi, pancakeSwapInfinityPositionManagerAbi, parseToStroops, parseTokenArrayFromJson, partnerInvariant, permit2Abi, polygonSupportedTokens, poolAbi, poolKeyAbi, randomUint256, rayDiv, rayMul, rayPow, rayToWad, recoveryInvariant, redbellySupportedTokens, relayConfig, relayTxAndWaitPacket, requestAddress, requestJsonRpc, requestSigning, resolveLogger, retry, reverseEncodeAddress, serializeAddressData, silentLogger, sleep, sodaxConfig, sodaxInvariant, solanaSupportedTokens, solverConfig, sonicSupportedTokens, sonicWalletFactoryAbi, spokeAssetManagerAbi, spokeChainConfig, spokeChainKeysSet, stacksSupportedTokens, stakedSodaAbi, stakingInvariant, stakingRouterAbi, stataTokenFactoryAbi, stellarSupportedTokens, submitTransaction, suiSupportedTokens, supportedSpokeChains, supportedTokensByChain, swapExactInSingleParamsAbi, swapInvariant, swapSupportedTokens, swapsConfig, uiPoolDataAbi, universalRouterAbi, unknownFailed, usesBip322MessageSigning, valueToBigNumber, valueToZDBigNumber, variableDebtTokenAbi, vaultTokenAbi, verifyFailed, wadToRay, waitForStacksTransaction, waitForTransactionReceipt, waitUntilIntentExecuted, walletFactoryAbi, wrappedSonicAbi };