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

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.cjs CHANGED
@@ -17,6 +17,7 @@ var anchor = require('@coral-xyz/anchor');
17
17
  var BN = require('bn.js');
18
18
  var IconSdkRaw = require('icon-sdk-js');
19
19
  var sdkTs = require('@injectivelabs/sdk-ts');
20
+ var tx_js = require('cosmjs-types/cosmos/tx/v1beta1/tx.js');
20
21
  var networks = require('@injectivelabs/networks');
21
22
  var BigNumber5 = require('bignumber.js');
22
23
  var swapSdkCore = require('@pancakeswap/swap-sdk-core');
@@ -197,7 +198,8 @@ var SODAX_FEATURES = [
197
198
  "migration",
198
199
  "dex",
199
200
  "partner",
200
- "recovery"
201
+ "recovery",
202
+ "leverageYield"
201
203
  ];
202
204
 
203
205
  // src/shared/utils/tiny-invariant.ts
@@ -330,7 +332,8 @@ var HubVaultSymbols = [
330
332
  "sodaNEAR",
331
333
  "sodaKAIA",
332
334
  "sodaSTX",
333
- "sodaUSDS"
335
+ "sodaUSDS",
336
+ "sodaJITOSOL"
334
337
  ];
335
338
  var SodaTokens = {
336
339
  sodaBNB: {
@@ -557,6 +560,45 @@ var SodaTokens = {
557
560
  chainKey: ChainKeys.SONIC_MAINNET,
558
561
  hubAsset: "0x243b0c26c8b38793908d7C64e8510f21B19B4613",
559
562
  vault: "0x243b0c26c8b38793908d7C64e8510f21B19B4613"
563
+ },
564
+ sodaJITOSOL: {
565
+ symbol: "sodaJITOSOL",
566
+ name: "Soda JITOSOL",
567
+ decimals: 18,
568
+ address: "0xe1bad4400d947Bc4fa66f9c0A143D800002083a0",
569
+ chainKey: ChainKeys.SONIC_MAINNET,
570
+ hubAsset: "0xe1bad4400d947Bc4fa66f9c0A143D800002083a0",
571
+ vault: "0xe1bad4400d947Bc4fa66f9c0A143D800002083a0"
572
+ }
573
+ };
574
+ var LsodaSymbols = ["lsodaWEETH", "lsodaWSTETH", "lsodaJITOSOL"];
575
+ var LsodaTokens = {
576
+ lsodaWEETH: {
577
+ symbol: "lsodaWEETH",
578
+ name: "Leveraged Soda weETH",
579
+ decimals: 18,
580
+ address: "0xD09de2f5070699A909c0FD32fb5A909d3886701D",
581
+ chainKey: ChainKeys.SONIC_MAINNET,
582
+ hubAsset: "0xD09de2f5070699A909c0FD32fb5A909d3886701D",
583
+ vault: "0xD09de2f5070699A909c0FD32fb5A909d3886701D"
584
+ },
585
+ lsodaWSTETH: {
586
+ symbol: "lsodaWSTETH",
587
+ name: "Leveraged Soda wstETH",
588
+ decimals: 18,
589
+ address: "0x136E5D1CEC5db1829E24941Eddd9C8640E02Ce7a",
590
+ chainKey: ChainKeys.SONIC_MAINNET,
591
+ hubAsset: "0x136E5D1CEC5db1829E24941Eddd9C8640E02Ce7a",
592
+ vault: "0x136E5D1CEC5db1829E24941Eddd9C8640E02Ce7a"
593
+ },
594
+ lsodaJITOSOL: {
595
+ symbol: "lsodaJITOSOL",
596
+ name: "Leveraged Soda JITOSOL",
597
+ decimals: 18,
598
+ address: "0xD7Ae4853E0f93682F5DaA14734F5D18cBa09Bd78",
599
+ chainKey: ChainKeys.SONIC_MAINNET,
600
+ hubAsset: "0xD7Ae4853E0f93682F5DaA14734F5D18cBa09Bd78",
601
+ vault: "0xD7Ae4853E0f93682F5DaA14734F5D18cBa09Bd78"
560
602
  }
561
603
  };
562
604
  var sonicSupportedTokens = {
@@ -623,7 +665,8 @@ var sonicSupportedTokens = {
623
665
  hubAsset: "0x7c7d53EEcda37a87ce0D5bf8E0b24512A48dC963",
624
666
  vault: SodaTokens.sodaSODA.address
625
667
  },
626
- ...SodaTokens
668
+ ...SodaTokens,
669
+ ...LsodaTokens
627
670
  };
628
671
  var redbellySupportedTokens = {
629
672
  RBNT: {
@@ -833,7 +876,7 @@ var solanaSupportedTokens = {
833
876
  address: "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn",
834
877
  chainKey: ChainKeys.SOLANA_MAINNET,
835
878
  hubAsset: "0x942f89a324d2652e447b9fcf08effc9f9776a680",
836
- vault: "0x942f89a324d2652e447b9fcf08effc9f9776a680"
879
+ vault: SodaTokens.sodaJITOSOL.address
837
880
  },
838
881
  mSOL: {
839
882
  symbol: "mSOL",
@@ -1266,6 +1309,15 @@ var baseSupportedTokens = {
1266
1309
  chainKey: ChainKeys.BASE_MAINNET,
1267
1310
  hubAsset: "0xaa81bb5ba3c972ab53605d3ba7e443a3de6d1cb9",
1268
1311
  vault: "0xaa81bb5ba3c972ab53605d3ba7e443a3de6d1cb9"
1312
+ },
1313
+ AERO: {
1314
+ symbol: "AERO",
1315
+ name: "Aerodrome Finance",
1316
+ decimals: 18,
1317
+ address: "0x940181a94A35A4569e4529A3CDfB74e38FD98631",
1318
+ chainKey: ChainKeys.BASE_MAINNET,
1319
+ hubAsset: "0x348e086ab6f424dfc575a325c28624ed23973173",
1320
+ vault: "0x348e086ab6f424dfc575a325c28624ed23973173"
1269
1321
  }
1270
1322
  };
1271
1323
  var optimismSupportedTokens = {
@@ -1948,6 +2000,33 @@ var stellarSupportedTokens = {
1948
2000
  chainKey: ChainKeys.STELLAR_MAINNET,
1949
2001
  hubAsset: "0xD749B5FfFED7cEDaa3239abDd16D677179C29AEc",
1950
2002
  vault: SodaTokens.sodaSODA.address
2003
+ },
2004
+ sodaETH: {
2005
+ symbol: "sodaETH",
2006
+ name: "Soda ETH",
2007
+ decimals: 7,
2008
+ address: "CDK5EWVTZLGSLI6D5OSES7XUKWZUKBXDRNOWUVDNPP5RJRP5EYWCW7SL",
2009
+ chainKey: ChainKeys.STELLAR_MAINNET,
2010
+ hubAsset: "0x4985a4b72ac723723e9ae82382d12d77e9a715de",
2011
+ vault: SodaTokens.sodaETH.address
2012
+ },
2013
+ sodaBTC: {
2014
+ symbol: "sodaBTC",
2015
+ name: "Soda BTC",
2016
+ decimals: 7,
2017
+ address: "CD6XWBW74YVFDQQYUM2GALCULMA5MAWGP6NTCWF3ZYXP4Z7MEVY4JKBX",
2018
+ chainKey: ChainKeys.STELLAR_MAINNET,
2019
+ hubAsset: "0xddee01f63c18843e2bac30cb702864d7632c83a2",
2020
+ vault: SodaTokens.sodaBTC.address
2021
+ },
2022
+ sodaBNB: {
2023
+ symbol: "sodaBNB",
2024
+ name: "Soda BNB",
2025
+ decimals: 7,
2026
+ address: "CCXTXZAFLVNTMORVWYB6BGL7YEW3U3ONDAL2FGBRGDUQH7AGANVQPRS6",
2027
+ chainKey: ChainKeys.STELLAR_MAINNET,
2028
+ hubAsset: "0xa10be5f5c2dea7d272555dc73ea2a7317c3c5b63",
2029
+ vault: SodaTokens.sodaBNB.address
1951
2030
  }
1952
2031
  };
1953
2032
  var suiSupportedTokens = {
@@ -3087,6 +3166,21 @@ var spokeChainConfig = {
3087
3166
  assetCode: "SODA",
3088
3167
  contractId: "CAH5LKJC2ZB4RVUVEVL2QWJWNJLHQE2UF767ILLQ5EQ4O3OURR2XIUGM",
3089
3168
  assetIssuer: "GDYUTHY75A7WUZJQDPOP66FB32BOYGZRXHWTWO4Q6LQTANT5X3V5HNFA"
3169
+ },
3170
+ {
3171
+ assetCode: "sodaETH",
3172
+ contractId: "CDK5EWVTZLGSLI6D5OSES7XUKWZUKBXDRNOWUVDNPP5RJRP5EYWCW7SL",
3173
+ assetIssuer: "GDYUTHY75A7WUZJQDPOP66FB32BOYGZRXHWTWO4Q6LQTANT5X3V5HNFA"
3174
+ },
3175
+ {
3176
+ assetCode: "sodaBTC",
3177
+ contractId: "CD6XWBW74YVFDQQYUM2GALCULMA5MAWGP6NTCWF3ZYXP4Z7MEVY4JKBX",
3178
+ assetIssuer: "GDYUTHY75A7WUZJQDPOP66FB32BOYGZRXHWTWO4Q6LQTANT5X3V5HNFA"
3179
+ },
3180
+ {
3181
+ assetCode: "sodaBNB",
3182
+ contractId: "CCXTXZAFLVNTMORVWYB6BGL7YEW3U3ONDAL2FGBRGDUQH7AGANVQPRS6",
3183
+ assetIssuer: "GDYUTHY75A7WUZJQDPOP66FB32BOYGZRXHWTWO4Q6LQTANT5X3V5HNFA"
3090
3184
  }
3091
3185
  ],
3092
3186
  supportedTokens: stellarSupportedTokens,
@@ -3362,7 +3456,8 @@ var moneyMarketSupportedTokens = {
3362
3456
  spokeChainConfig[ChainKeys.SOLANA_MAINNET].supportedTokens.bnUSD,
3363
3457
  spokeChainConfig[ChainKeys.SOLANA_MAINNET].supportedTokens.USDC,
3364
3458
  spokeChainConfig[ChainKeys.SOLANA_MAINNET].supportedTokens.SODA,
3365
- spokeChainConfig[ChainKeys.SOLANA_MAINNET].supportedTokens.USDT
3459
+ spokeChainConfig[ChainKeys.SOLANA_MAINNET].supportedTokens.USDT,
3460
+ spokeChainConfig[ChainKeys.SOLANA_MAINNET].supportedTokens.JitoSOL
3366
3461
  ],
3367
3462
  [ChainKeys.ICON_MAINNET]: [
3368
3463
  // spokeChainConfig[ChainKeys.ICON].supportedTokens.ICX,
@@ -3373,7 +3468,10 @@ var moneyMarketSupportedTokens = {
3373
3468
  spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.XLM,
3374
3469
  spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.bnUSD,
3375
3470
  spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.SODA,
3376
- spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.USDC
3471
+ spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.USDC,
3472
+ spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.sodaETH,
3473
+ spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.sodaBTC,
3474
+ spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.sodaBNB
3377
3475
  ],
3378
3476
  [ChainKeys.SUI_MAINNET]: [
3379
3477
  spokeChainConfig[ChainKeys.SUI_MAINNET].supportedTokens.SUI,
@@ -3624,7 +3722,9 @@ var swapSupportedTokens = {
3624
3722
  spokeChainConfig[ChainKeys.SONIC_MAINNET].supportedTokens.USDT,
3625
3723
  spokeChainConfig[ChainKeys.SONIC_MAINNET].supportedTokens.wS,
3626
3724
  spokeChainConfig[ChainKeys.SONIC_MAINNET].supportedTokens.SODA,
3627
- ...Object.values(SodaTokens)
3725
+ // sodaUSDS is staging-only — see stagingSwapSupportedTokens
3726
+ ...Object.values(SodaTokens).filter((t) => t !== SodaTokens.sodaUSDS),
3727
+ ...Object.values(LsodaTokens)
3628
3728
  ],
3629
3729
  [ChainKeys.AVALANCHE_MAINNET]: [
3630
3730
  spokeChainConfig[ChainKeys.AVALANCHE_MAINNET].supportedTokens.AVAX,
@@ -3643,36 +3743,35 @@ var swapSupportedTokens = {
3643
3743
  spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.tBTC,
3644
3744
  spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.USDC,
3645
3745
  spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.USDT,
3646
- spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.SODA,
3647
3746
  spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.ARB,
3648
3747
  spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.AAVE,
3649
3748
  spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.LINK,
3650
3749
  spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.UNI,
3651
3750
  spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.CRV,
3652
3751
  spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.PENDLE,
3653
- spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.rETH
3752
+ spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.rETH,
3753
+ spokeChainConfig[ChainKeys.ARBITRUM_MAINNET].supportedTokens.SODA
3654
3754
  ],
3655
3755
  [ChainKeys.BASE_MAINNET]: [
3656
3756
  spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.ETH,
3657
- spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.bnUSD,
3658
3757
  spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.weETH,
3659
3758
  spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.USDC,
3660
3759
  spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.wstETH,
3661
3760
  spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.cbBTC,
3662
- spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.SODA,
3663
3761
  spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.VIRTUAL,
3664
- spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.cbETH
3762
+ spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.cbETH,
3763
+ spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.SODA
3665
3764
  ],
3666
3765
  [ChainKeys.OPTIMISM_MAINNET]: [
3667
3766
  spokeChainConfig[ChainKeys.OPTIMISM_MAINNET].supportedTokens.ETH,
3668
- spokeChainConfig[ChainKeys.OPTIMISM_MAINNET].supportedTokens.bnUSD,
3669
3767
  spokeChainConfig[ChainKeys.OPTIMISM_MAINNET].supportedTokens.USDC,
3670
3768
  spokeChainConfig[ChainKeys.OPTIMISM_MAINNET].supportedTokens.wstETH,
3671
3769
  // spokeChainConfig[OPTIMISM_MAINNET_CHAIN_ID].supportedTokens.weETH, // NOTE: Not Implemented
3672
3770
  spokeChainConfig[ChainKeys.OPTIMISM_MAINNET].supportedTokens.USDT,
3673
3771
  spokeChainConfig[ChainKeys.OPTIMISM_MAINNET].supportedTokens.SODA,
3674
3772
  spokeChainConfig[ChainKeys.OPTIMISM_MAINNET].supportedTokens.OP,
3675
- spokeChainConfig[ChainKeys.OPTIMISM_MAINNET].supportedTokens.WBTC
3773
+ spokeChainConfig[ChainKeys.OPTIMISM_MAINNET].supportedTokens.WBTC,
3774
+ spokeChainConfig[ChainKeys.OPTIMISM_MAINNET].supportedTokens.bnUSD
3676
3775
  ],
3677
3776
  [ChainKeys.POLYGON_MAINNET]: [
3678
3777
  spokeChainConfig[ChainKeys.POLYGON_MAINNET].supportedTokens.POL,
@@ -3728,7 +3827,6 @@ var swapSupportedTokens = {
3728
3827
  spokeChainConfig[ChainKeys.LIGHTLINK_MAINNET].supportedTokens["SUI.LL"],
3729
3828
  spokeChainConfig[ChainKeys.LIGHTLINK_MAINNET].supportedTokens["S.LL"],
3730
3829
  spokeChainConfig[ChainKeys.LIGHTLINK_MAINNET].supportedTokens["POL.LL"],
3731
- spokeChainConfig[ChainKeys.LIGHTLINK_MAINNET].supportedTokens["HYPE.LL"],
3732
3830
  spokeChainConfig[ChainKeys.LIGHTLINK_MAINNET].supportedTokens.LL
3733
3831
  ],
3734
3832
  [ChainKeys.SOLANA_MAINNET]: [
@@ -3767,7 +3865,10 @@ var swapSupportedTokens = {
3767
3865
  spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.bnUSD,
3768
3866
  // NOTE: Not Implemented
3769
3867
  spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.USDC,
3770
- spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.SODA
3868
+ spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.SODA,
3869
+ spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.sodaETH,
3870
+ spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.sodaBTC,
3871
+ spokeChainConfig[ChainKeys.STELLAR_MAINNET].supportedTokens.sodaBNB
3771
3872
  ],
3772
3873
  [ChainKeys.SUI_MAINNET]: [
3773
3874
  spokeChainConfig[ChainKeys.SUI_MAINNET].supportedTokens.SUI,
@@ -3785,12 +3886,8 @@ var swapSupportedTokens = {
3785
3886
  spokeChainConfig[ChainKeys.SUI_MAINNET].supportedTokens.WAL,
3786
3887
  spokeChainConfig[ChainKeys.SUI_MAINNET].supportedTokens.NAVX
3787
3888
  ],
3788
- [ChainKeys.INJECTIVE_MAINNET]: [
3789
- spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.INJ,
3790
- spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.bnUSD,
3791
- spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.USDC
3792
- // spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.SODA, // NOTE: not in solver wiki
3793
- ],
3889
+ // Injective is currently staging-only — see stagingSwapSupportedTokens
3890
+ [ChainKeys.INJECTIVE_MAINNET]: [],
3794
3891
  [ChainKeys.NEAR_MAINNET]: [
3795
3892
  spokeChainConfig[ChainKeys.NEAR_MAINNET].supportedTokens.NEAR,
3796
3893
  spokeChainConfig[ChainKeys.NEAR_MAINNET].supportedTokens.bnUSD,
@@ -3857,24 +3954,112 @@ var swapSupportedTokens = {
3857
3954
  spokeChainConfig[ChainKeys.STACKS_MAINNET].supportedTokens.USDC
3858
3955
  ]
3859
3956
  };
3957
+ var stagingSwapSupportedTokens = {
3958
+ [ChainKeys.SONIC_MAINNET]: [SodaTokens.sodaUSDS],
3959
+ [ChainKeys.AVALANCHE_MAINNET]: [],
3960
+ [ChainKeys.ARBITRUM_MAINNET]: [],
3961
+ [ChainKeys.BASE_MAINNET]: [
3962
+ spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.bnUSD,
3963
+ spokeChainConfig[ChainKeys.BASE_MAINNET].supportedTokens.AERO
3964
+ ],
3965
+ [ChainKeys.OPTIMISM_MAINNET]: [],
3966
+ [ChainKeys.POLYGON_MAINNET]: [
3967
+ spokeChainConfig[ChainKeys.POLYGON_MAINNET].supportedTokens.USDT,
3968
+ spokeChainConfig[ChainKeys.POLYGON_MAINNET].supportedTokens.wstETH
3969
+ ],
3970
+ [ChainKeys.BSC_MAINNET]: [],
3971
+ [ChainKeys.HYPEREVM_MAINNET]: [],
3972
+ [ChainKeys.LIGHTLINK_MAINNET]: [
3973
+ spokeChainConfig[ChainKeys.LIGHTLINK_MAINNET].supportedTokens["HYPE.LL"]
3974
+ ],
3975
+ [ChainKeys.SOLANA_MAINNET]: [],
3976
+ [ChainKeys.ICON_MAINNET]: [],
3977
+ [ChainKeys.STELLAR_MAINNET]: [],
3978
+ [ChainKeys.SUI_MAINNET]: [spokeChainConfig[ChainKeys.SUI_MAINNET].supportedTokens.USDT],
3979
+ [ChainKeys.INJECTIVE_MAINNET]: [
3980
+ spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.INJ,
3981
+ spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.bnUSD,
3982
+ spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.USDC
3983
+ // spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.SODA, // NOTE: not in solver wiki
3984
+ ],
3985
+ [ChainKeys.NEAR_MAINNET]: [],
3986
+ [ChainKeys.BITCOIN_MAINNET]: [],
3987
+ [ChainKeys.ETHEREUM_MAINNET]: [
3988
+ spokeChainConfig[ChainKeys.ETHEREUM_MAINNET].supportedTokens.wstETH,
3989
+ spokeChainConfig[ChainKeys.ETHEREUM_MAINNET].supportedTokens.weETH
3990
+ ],
3991
+ [ChainKeys.REDBELLY_MAINNET]: [],
3992
+ [ChainKeys.KAIA_MAINNET]: [],
3993
+ [ChainKeys.STACKS_MAINNET]: []
3994
+ };
3860
3995
  var swapsConfig = {
3861
- partnerFee: void 0,
3862
3996
  supportedTokens: swapSupportedTokens
3863
3997
  };
3864
3998
  var getSupportedSolverTokens = (chainId) => swapSupportedTokens[chainId];
3865
- var isSwapSupportedToken = (chainId, token) => swapSupportedTokens[chainId].some((t) => t.address.toLowerCase() === token.toLowerCase());
3999
+ var getStagingSolverTokens = (chainId) => [
4000
+ ...swapSupportedTokens[chainId],
4001
+ ...stagingSwapSupportedTokens[chainId]
4002
+ ];
4003
+ var isSwapSupportedToken = (chainId, token) => [...swapSupportedTokens[chainId], ...stagingSwapSupportedTokens[chainId]].some((t) => t.address.toLowerCase() === token.toLowerCase());
3866
4004
 
3867
- // ../types/dist/sodax-config/sodax-config.js
3868
- var bridgeConfig = {
3869
- partnerFee: void 0
4005
+ // ../types/dist/leverageYield/leverageYield.js
4006
+ var leverageYieldVaults = [
4007
+ {
4008
+ name: LsodaTokens.lsodaWEETH.symbol,
4009
+ vault: LsodaTokens.lsodaWEETH.vault,
4010
+ asset: SodaTokens.sodaWEETH.address,
4011
+ // sodaWEETH on Sonic
4012
+ borrowToken: SodaTokens.sodaETH.address,
4013
+ // sodaETH on Sonic
4014
+ lsdSource: {
4015
+ // DefiLlama pool for EtherFi's weETH on Ethereum (project: 'ether.fi-stake').
4016
+ poolId: "46bd2bdf-6d92-4066-b482-e885ee172264",
4017
+ fallbackAprPct: 3,
4018
+ label: "EtherFi (weETH)"
4019
+ }
4020
+ },
4021
+ {
4022
+ name: LsodaTokens.lsodaWSTETH.symbol,
4023
+ vault: LsodaTokens.lsodaWSTETH.vault,
4024
+ asset: SodaTokens.sodaWSTETH.address,
4025
+ // sodaWSTETH on Sonic
4026
+ borrowToken: SodaTokens.sodaETH.address,
4027
+ // sodaETH on Sonic
4028
+ lsdSource: {
4029
+ // DefiLlama pool for Lido's stETH on Ethereum (wstETH inherits this rate via redeem).
4030
+ poolId: "747c1d2a-c668-4682-b9f9-296708a3dd90",
4031
+ fallbackAprPct: 2.4,
4032
+ label: "Lido (stETH)"
4033
+ }
4034
+ },
4035
+ {
4036
+ name: LsodaTokens.lsodaJITOSOL.symbol,
4037
+ vault: LsodaTokens.lsodaJITOSOL.vault,
4038
+ asset: SodaTokens.sodaJITOSOL.address,
4039
+ // sodaJITOSOL on Sonic
4040
+ borrowToken: SodaTokens.sodaSOL.address,
4041
+ // sodaSOL on Sonic
4042
+ lsdSource: {
4043
+ // DefiLlama pool for Jito's JitoSOL native staking on Solana (project: 'jito-liquid-staking').
4044
+ poolId: "0e7d0722-9054-4907-8593-567b353c0900",
4045
+ fallbackAprPct: 5.5,
4046
+ label: "Jito (JitoSOL)"
4047
+ }
4048
+ }
4049
+ ];
4050
+ var leverageYieldConfig = {
4051
+ vaults: leverageYieldVaults
3870
4052
  };
4053
+
4054
+ // ../types/dist/sodax-config/sodax-config.js
4055
+ var bridgeConfig = {};
3871
4056
  var sodaxConfig = {
3872
- fee: void 0,
3873
4057
  chains: spokeChainConfig,
3874
4058
  swaps: swapsConfig,
3875
4059
  moneyMarket: moneyMarketConfig,
3876
4060
  bridge: bridgeConfig,
3877
4061
  dex: dexConfig,
4062
+ leverageYield: leverageYieldConfig,
3878
4063
  hub: hubConfig,
3879
4064
  api: apiConfig,
3880
4065
  solver: solverConfig,
@@ -4016,7 +4201,7 @@ function isValidWalletProviderForChainKey(chainKey, walletProvider) {
4016
4201
  }
4017
4202
 
4018
4203
  // ../types/dist/index.js
4019
- var CONFIG_VERSION = 210;
4204
+ var CONFIG_VERSION = 212;
4020
4205
  function isEvmSpokeChainConfig(value) {
4021
4206
  return typeof value === "object" && value !== null && value.chain.type === "EVM" && value.chain.key !== HUB_CHAIN_KEY;
4022
4207
  }
@@ -4403,7 +4588,10 @@ async function pollForExecutedPacket(payload) {
4403
4588
  }
4404
4589
  const txPackets = txPacketsResult.value;
4405
4590
  if (txPackets.success && txPackets.data.length > 0) {
4406
- const packet = txPackets.data.find((packet2) => packet2.src_tx_hash.toLowerCase() === payload.srcTxHash.toLowerCase());
4591
+ const candidates = txPackets.data.filter(
4592
+ (packet2) => packet2.src_tx_hash.toLowerCase() === payload.srcTxHash.toLowerCase()
4593
+ );
4594
+ const packet = payload.selectPacket ? payload.selectPacket(candidates) : candidates[0];
4407
4595
  if (packet?.status === "executed") {
4408
4596
  return { kind: "found", packet };
4409
4597
  }
@@ -13293,14 +13481,7 @@ function deepMerge(target, source) {
13293
13481
 
13294
13482
  // src/shared/config/mergeSodaxConfig.ts
13295
13483
  function mergeSodaxConfig(base2, override) {
13296
- const merged = deepMerge(base2, override);
13297
- if (override.fee !== void 0) {
13298
- merged.fee = override.fee;
13299
- }
13300
- if (override.bridge?.partnerFee !== void 0) {
13301
- merged.bridge.partnerFee = override.bridge.partnerFee;
13302
- }
13303
- return merged;
13484
+ return deepMerge(base2, override);
13304
13485
  }
13305
13486
 
13306
13487
  // src/shared/logger.ts
@@ -13340,6 +13521,12 @@ var ConfigService = class {
13340
13521
  * {@link initialize}'s dynamic-config swap never clobbers it. Read by services via `config.logger`.
13341
13522
  */
13342
13523
  logger;
13524
+ /**
13525
+ * Global partner fee. Resolved once at construction and kept independent of {@link sodax} so that
13526
+ * {@link initialize}'s dynamic-config swap never clobbers it. The backend never supplies it — it is
13527
+ * a client-side option set via `new Sodax({ fee })`. Per-feature overrides live on the feature config.
13528
+ */
13529
+ fee;
13343
13530
  initialized = false;
13344
13531
  // data structures for quick lookup
13345
13532
  supportedHubAssetsSet;
@@ -13351,11 +13538,12 @@ var ConfigService = class {
13351
13538
  stakedATokenAddressesSet;
13352
13539
  chainToSupportedTokenAddressMap;
13353
13540
  hubAssetToXTokenMap;
13354
- constructor({ api, config, userConfig, logger }) {
13541
+ constructor({ api, config, userConfig, logger, fee }) {
13355
13542
  this.api = api;
13356
13543
  this.sodax = config;
13357
13544
  this.userConfig = userConfig;
13358
13545
  this.logger = logger ?? resolveLogger(void 0);
13546
+ this.fee = fee;
13359
13547
  this.loadSodaxConfigDataStructures(config);
13360
13548
  }
13361
13549
  async initialize() {
@@ -13588,6 +13776,24 @@ var ConfigService = class {
13588
13776
  get moneyMarket() {
13589
13777
  return this.sodax.moneyMarket;
13590
13778
  }
13779
+ get leverageYield() {
13780
+ return this.sodax.leverageYield;
13781
+ }
13782
+ // Effective partner fee per feature: the feature-specific override if set, otherwise the global
13783
+ // `fee` client option ({@link fee}). The global fee is the default, overridable per-feature. `??`
13784
+ // (never a merge) keeps the chosen PartnerFee variant intact — no discriminated-union hybrid.
13785
+ get swapPartnerFee() {
13786
+ return this.swaps.partnerFee ?? this.fee;
13787
+ }
13788
+ get moneyMarketPartnerFee() {
13789
+ return this.moneyMarket.partnerFee ?? this.fee;
13790
+ }
13791
+ get bridgePartnerFee() {
13792
+ return this.bridge.partnerFee ?? this.fee;
13793
+ }
13794
+ get leverageYieldPartnerFee() {
13795
+ return this.leverageYield.partnerFee ?? this.fee;
13796
+ }
13591
13797
  get dex() {
13592
13798
  return this.sodax.dex;
13593
13799
  }
@@ -14399,12 +14605,23 @@ var StacksSpokeService = class {
14399
14605
  postConditionMode: core.PostConditionMode.Allow
14400
14606
  };
14401
14607
  if (params.raw === true) {
14402
- if (core.validateStacksAddress(params.srcAddress)) {
14403
- throw new Error('When using raw transactions, the public key must be provided as "from" parameter');
14608
+ if (!params.srcPublicKey) {
14609
+ throw new Error("Stacks raw transactions require srcPublicKey (the signer public key for srcAddress).");
14610
+ }
14611
+ let derivedAddress;
14612
+ try {
14613
+ derivedAddress = core.getAddressFromPublicKey(params.srcPublicKey, this.network);
14614
+ } catch (error) {
14615
+ throw new Error(`srcPublicKey is not a valid Stacks public key: ${error.message}`);
14616
+ }
14617
+ if (derivedAddress !== params.srcAddress) {
14618
+ throw new Error(
14619
+ `srcPublicKey does not match srcAddress: it derives ${derivedAddress}, but srcAddress is ${params.srcAddress}.`
14620
+ );
14404
14621
  }
14405
14622
  const tx = await core.makeUnsignedContractCall({
14406
14623
  ...reqData,
14407
- publicKey: params.srcAddress,
14624
+ publicKey: params.srcPublicKey,
14408
14625
  network: this.network,
14409
14626
  fee: 0,
14410
14627
  // placeholder — we'll estimate
@@ -17360,8 +17577,8 @@ function chain(...args) {
17360
17577
  const id = (a) => a;
17361
17578
  const wrap = (a, b) => (c) => a(b(c));
17362
17579
  const encode3 = args.map((x) => x.encode).reduceRight(wrap, id);
17363
- const decode = args.map((x) => x.decode).reduce(wrap, id);
17364
- return { encode: encode3, decode };
17580
+ const decode2 = args.map((x) => x.decode).reduce(wrap, id);
17581
+ return { encode: encode3, decode: decode2 };
17365
17582
  }
17366
17583
  // @__NO_SIDE_EFFECTS__
17367
17584
  function alphabet(letters) {
@@ -22295,17 +22512,11 @@ var SuiSpokeService = class {
22295
22512
  ]
22296
22513
  });
22297
22514
  if (params.raw === true) {
22298
- tx.setSender(from);
22299
- const transactionRaw = await tx.build({
22300
- client: this.publicClient,
22301
- onlyTransactionKind: true
22302
- });
22303
- const transactionRawBase64String = Buffer.from(transactionRaw).toString("base64");
22304
22515
  return {
22305
22516
  from,
22306
22517
  to: `${assetManager.packageId}::${assetManager.moduleId}::transfer`,
22307
22518
  value: amount,
22308
- data: transactionRawBase64String
22519
+ data: tx.serialize()
22309
22520
  };
22310
22521
  }
22311
22522
  return params.walletProvider.signAndExecuteTxn(tx);
@@ -22325,17 +22536,11 @@ var SuiSpokeService = class {
22325
22536
  ]
22326
22537
  });
22327
22538
  if (params.raw === true) {
22328
- txb.setSender(from);
22329
- const transactionRaw = await txb.build({
22330
- client: this.publicClient,
22331
- onlyTransactionKind: true
22332
- });
22333
- const transactionRawBase64String = Buffer.from(transactionRaw).toString("base64");
22334
22539
  return {
22335
22540
  from,
22336
22541
  to: `${connection.packageId}::${connection.moduleId}::send_message_ua`,
22337
22542
  value: 0n,
22338
- data: transactionRawBase64String
22543
+ data: txb.serialize()
22339
22544
  };
22340
22545
  }
22341
22546
  return params.walletProvider.signAndExecuteTxn(txb);
@@ -22346,7 +22551,7 @@ var SuiSpokeService = class {
22346
22551
  * @returns {Promise<bigint>} The estimated computation cost.
22347
22552
  */
22348
22553
  async estimateGas({ tx }) {
22349
- const txb = transactions.Transaction.fromKind(tx.data);
22554
+ const txb = transactions.Transaction.from(tx.data);
22350
22555
  const result = await this.publicClient.devInspectTransactionBlock({
22351
22556
  sender: tx.from,
22352
22557
  transactionBlock: txb
@@ -22577,6 +22782,7 @@ var CustomStellarAccount = class {
22577
22782
  decrementSequenceNumber() {
22578
22783
  if (this.sequenceNumber > this.startingSequenceNumber) {
22579
22784
  this.sequenceNumber--;
22785
+ return;
22580
22786
  }
22581
22787
  throw new Error(
22582
22788
  `Sequence number cannot be decremented below the starting sequence number: ${this.startingSequenceNumber}`
@@ -22683,7 +22889,7 @@ var StellarSpokeService = class {
22683
22889
  );
22684
22890
  const assembledPriorityTx = stellarSdk.rpc.assembleTransaction(rawPriorityTx, simulation).build();
22685
22891
  if (params.raw) {
22686
- const transactionXdr = rawPriorityTx.toXDR();
22892
+ const transactionXdr = assembledPriorityTx.toXDR();
22687
22893
  return {
22688
22894
  from,
22689
22895
  to: this.config.getChainConfig(srcChainKey).addresses.assetManager,
@@ -22800,7 +23006,7 @@ var StellarSpokeService = class {
22800
23006
  );
22801
23007
  const assembledPriorityTx = stellarSdk.rpc.assembleTransaction(rawPriorityTx, simulation).build();
22802
23008
  if (params.raw) {
22803
- const transactionXdr = rawPriorityTx.toXDR();
23009
+ const transactionXdr = assembledPriorityTx.toXDR();
22804
23010
  return {
22805
23011
  from,
22806
23012
  to: this.config.getChainConfig(srcChainKey).addresses.assetManager,
@@ -23473,6 +23679,8 @@ var IconSpokeService = class {
23473
23679
  };
23474
23680
  }
23475
23681
  };
23682
+ var GAS_BUFFER_MULTIPLIER = 1.2;
23683
+ var GAS_PRICE_REGEX = /^(\d+)(.*)$/;
23476
23684
  var InjectiveSpokeService = class {
23477
23685
  config;
23478
23686
  chainGrpcWasmApi;
@@ -23480,6 +23688,7 @@ var InjectiveSpokeService = class {
23480
23688
  endpoints;
23481
23689
  pollingIntervalMs;
23482
23690
  maxTimeoutMs;
23691
+ gasPrice;
23483
23692
  constructor(config) {
23484
23693
  this.config = config;
23485
23694
  this.endpoints = networks.getNetworkEndpoints(networks.Network.Mainnet);
@@ -23487,6 +23696,16 @@ var InjectiveSpokeService = class {
23487
23696
  this.txClient = new sdkTs.TxGrpcApi(this.endpoints.grpc);
23488
23697
  this.pollingIntervalMs = this.config.sodaxConfig.chains[ChainKeys.INJECTIVE_MAINNET].pollingConfig.pollingIntervalMs;
23489
23698
  this.maxTimeoutMs = this.config.sodaxConfig.chains[ChainKeys.INJECTIVE_MAINNET].pollingConfig.maxTimeoutMs;
23699
+ this.gasPrice = this.config.getChainConfig(ChainKeys.INJECTIVE_MAINNET).gasPrice;
23700
+ }
23701
+ /** Parse a chain-config gas price like `"500000000inj"` into its numeric price and denom. */
23702
+ parseGasPrice(gasPrice) {
23703
+ const match = GAS_PRICE_REGEX.exec(gasPrice);
23704
+ const price = match?.[1];
23705
+ if (price === void 0) {
23706
+ throw new Error(`Invalid Injective gasPrice config: ${gasPrice}`);
23707
+ }
23708
+ return { price: BigInt(price), denom: match?.[2] || "inj" };
23490
23709
  }
23491
23710
  /**
23492
23711
  * Estimate the gas for a transaction.
@@ -23495,7 +23714,7 @@ var InjectiveSpokeService = class {
23495
23714
  * @returns {Promise<InjectiveGasEstimate>} The estimated gas for the transaction.
23496
23715
  */
23497
23716
  async estimateGas({ tx }) {
23498
- const txRaw = sdkTs.CosmosTxV1Beta1TxPb.TxRaw.fromPartial({
23717
+ const txRaw = tx_js.TxRaw.fromPartial({
23499
23718
  bodyBytes: tx.signedDoc.bodyBytes,
23500
23719
  authInfoBytes: tx.signedDoc.authInfoBytes,
23501
23720
  signatures: []
@@ -23534,7 +23753,9 @@ var InjectiveSpokeService = class {
23534
23753
  chainConfig.networkId,
23535
23754
  from,
23536
23755
  chainConfig.addresses.assetManager,
23537
- msg
23756
+ msg,
23757
+ void 0,
23758
+ funds
23538
23759
  );
23539
23760
  }
23540
23761
  const res = await params.walletProvider.execute(from, chainConfig.addresses.assetManager, msg, funds);
@@ -23555,27 +23776,50 @@ var InjectiveSpokeService = class {
23555
23776
  );
23556
23777
  return BigInt(sdkTs.fromBase64(response.data));
23557
23778
  }
23558
- async getRawTransaction(chainId, senderAddress, contractAddress, msg, memo) {
23779
+ async getRawTransaction(chainId, senderAddress, contractAddress, msg, memo, funds = []) {
23559
23780
  const msgExec = sdkTs.MsgExecuteContract.fromJSON({
23560
23781
  contractAddress,
23561
23782
  sender: senderAddress,
23562
23783
  msg,
23563
- funds: []
23784
+ funds
23564
23785
  });
23565
- const { txRaw } = await sdkTs.createTransactionForAddressAndMsg({
23786
+ const accountResponse = await new sdkTs.ChainRestAuthApi(this.endpoints.rest).fetchCosmosAccount(senderAddress);
23787
+ const baseAccount = sdkTs.BaseAccount.fromRestCosmosApi(accountResponse);
23788
+ const pubKey = baseAccount.pubKey.key;
23789
+ if (!pubKey) {
23790
+ throw new Error(`The pubKey for ${senderAddress} is missing \u2014 the account has not signed a transaction yet.`);
23791
+ }
23792
+ const txArgs = {
23566
23793
  message: msgExec,
23567
23794
  memo: memo || "",
23568
- address: senderAddress,
23569
- endpoint: this.endpoints.grpc,
23795
+ pubKey,
23796
+ sequence: baseAccount.sequence,
23797
+ accountNumber: baseAccount.accountNumber,
23570
23798
  chainId
23571
- });
23799
+ };
23800
+ const draft = sdkTs.createTransaction(txArgs);
23801
+ const { gasInfo } = await this.txClient.simulate(
23802
+ tx_js.TxRaw.fromPartial({
23803
+ bodyBytes: draft.txRaw.bodyBytes,
23804
+ authInfoBytes: draft.txRaw.authInfoBytes,
23805
+ signatures: []
23806
+ // not required for simulation
23807
+ })
23808
+ );
23809
+ const gas = Math.ceil(gasInfo.gasUsed * GAS_BUFFER_MULTIPLIER);
23810
+ const { price, denom } = this.parseGasPrice(this.gasPrice);
23811
+ const fee = {
23812
+ amount: [{ denom, amount: (BigInt(gas) * price).toString() }],
23813
+ gas: gas.toString()
23814
+ };
23815
+ const { txRaw, signDoc } = sdkTs.createTransaction({ ...txArgs, fee });
23572
23816
  const rawTx = {
23573
23817
  from: senderAddress,
23574
23818
  to: contractAddress,
23575
23819
  signedDoc: {
23576
23820
  bodyBytes: txRaw.bodyBytes,
23577
23821
  chainId,
23578
- accountNumber: BigInt(0),
23822
+ accountNumber: BigInt(signDoc.accountNumber),
23579
23823
  authInfoBytes: txRaw.authInfoBytes
23580
23824
  }
23581
23825
  };
@@ -25714,6 +25958,24 @@ var SolverApiService = class {
25714
25958
  }
25715
25959
  }
25716
25960
  };
25961
+ function decodePacketIntentTarget(payload) {
25962
+ try {
25963
+ const hex = payload.startsWith("0x") ? payload.slice(2) : payload;
25964
+ const decoded = rlp__namespace.decode(Buffer.from(hex, "hex"));
25965
+ const field1 = decoded?.[1];
25966
+ if (!field1 || field1.length === 0) return void 0;
25967
+ return `0x${Buffer.from(field1).toString("hex")}`.toLowerCase();
25968
+ } catch {
25969
+ return void 0;
25970
+ }
25971
+ }
25972
+ function selectSolvedIntentPacket(packets, intentsContract) {
25973
+ if (packets.length <= 1) return packets[0];
25974
+ const target = intentsContract.toLowerCase();
25975
+ const matched = packets.find((packet) => decodePacketIntentTarget(packet.payload) === target);
25976
+ if (matched) return matched;
25977
+ return packets.reduce((highest, packet) => packet.conn_sn > highest.conn_sn ? packet : highest);
25978
+ }
25717
25979
 
25718
25980
  // src/swap/errors.ts
25719
25981
  var swapInvariant = createInvariant("swap");
@@ -25749,7 +26011,7 @@ var SwapService = class {
25749
26011
  relayerApiEndpoint;
25750
26012
  constructor({ config, hubProvider, spoke }) {
25751
26013
  this.solver = config.solver;
25752
- this.partnerFee = config.swaps.partnerFee;
26014
+ this.partnerFee = config.swapPartnerFee;
25753
26015
  this.relayerApiEndpoint = config.relay.relayerApiEndpoint;
25754
26016
  this.config = config;
25755
26017
  this.hubProvider = hubProvider;
@@ -25767,10 +26029,13 @@ var SwapService = class {
25767
26029
  /**
25768
26030
  * Requests a price quote from the solver API for a given token pair and amount.
25769
26031
  *
25770
- * Adjusts `payload.amount` by the configured partner fee before forwarding to the solver,
25771
- * so the returned `quoted_amount` reflects the net output the user actually receives.
26032
+ * Adjusts `payload.amount` by the partner fee before forwarding to the solver, so the returned
26033
+ * `quoted_amount` reflects the net output the user actually receives. Pass `partnerFee` to match
26034
+ * a per-action override supplied to `createIntent` (`extras.partnerFee`); omit it to use the
26035
+ * configured swap fee.
25772
26036
  *
25773
- * @param payload - Source/destination tokens, chain IDs, input amount, and quote type.
26037
+ * @param payload - The solver quote request, optionally carrying a per-call `partnerFee` override
26038
+ * (defaults to the configured swap partner fee). `partnerFee` is stripped before forwarding.
25774
26039
  * @returns A `Result` containing `{ quoted_amount: bigint }` on success, or a
25775
26040
  * `SolverErrorResponse` (with a `SolverIntentErrorCode`) on failure.
25776
26041
  *
@@ -25786,11 +26051,12 @@ var SwapService = class {
25786
26051
  * if (response.ok) console.log('Quoted amount:', response.value.quoted_amount);
25787
26052
  */
25788
26053
  async getQuote(payload) {
25789
- payload = {
25790
- ...payload,
25791
- amount: adjustAmountByFee(payload.amount, this.partnerFee, payload.quote_type)
26054
+ const { partnerFee = this.partnerFee, ...request } = payload;
26055
+ const adjustedPayload = {
26056
+ ...request,
26057
+ amount: adjustAmountByFee(request.amount, partnerFee, request.quote_type)
25792
26058
  };
25793
- return SolverApiService.getQuote(payload, this.solver, this.config);
26059
+ return SolverApiService.getQuote(adjustedPayload, this.solver, this.config);
25794
26060
  }
25795
26061
  /**
25796
26062
  * Calculates the partner fee that will be deducted from the given input amount.
@@ -26140,7 +26406,8 @@ var SwapService = class {
26140
26406
  * - `UNKNOWN` — defensive fallback.
26141
26407
  */
26142
26408
  async createIntent(_params) {
26143
- const { params, skipSimulation } = _params;
26409
+ const { params, skipSimulation, extras } = _params;
26410
+ const partnerFee = extras?.partnerFee ?? this.partnerFee;
26144
26411
  const baseCtx = { srcChainKey: params.srcChainKey, dstChainKey: params.dstChainKey };
26145
26412
  try {
26146
26413
  swapInvariant(
@@ -26175,6 +26442,13 @@ var SwapService = class {
26175
26442
  { ...baseCtx, field: "minOutputAmount" }
26176
26443
  );
26177
26444
  }
26445
+ if (isStacksChainKeyType(params.srcChainKey) && _params.raw === true) {
26446
+ swapInvariant(
26447
+ extras?.srcPublicKey !== void 0,
26448
+ "srcPublicKey is required for Stacks createIntent (raw) \u2014 the source tx is built unsigned and needs the signer public key",
26449
+ { ...baseCtx, field: "srcPublicKey" }
26450
+ );
26451
+ }
26178
26452
  const personalAddress = params.srcAddress;
26179
26453
  let walletAddress = personalAddress;
26180
26454
  if (isBitcoinChainKeyType(params.srcChainKey) && _params.raw === false) {
@@ -26192,7 +26466,7 @@ var SwapService = class {
26192
26466
  createIntentParams: params,
26193
26467
  creatorHubWalletAddress,
26194
26468
  solverConfig: this.solver,
26195
- fee: this.config.swaps.partnerFee,
26469
+ fee: partnerFee,
26196
26470
  hubProvider: this.hubProvider
26197
26471
  };
26198
26472
  const [txResult2, intent2, feeAmount2, data2] = await SonicSpokeService.createSwapIntent(
@@ -26218,11 +26492,12 @@ var SwapService = class {
26218
26492
  },
26219
26493
  creatorHubWalletAddress,
26220
26494
  this.config,
26221
- this.config.swaps.partnerFee
26495
+ partnerFee
26222
26496
  );
26223
26497
  const coreDepositParams = {
26224
26498
  srcChainKey: params.srcChainKey,
26225
26499
  srcAddress: walletAddress,
26500
+ srcPublicKey: extras?.srcPublicKey,
26226
26501
  to: creatorHubWalletAddress,
26227
26502
  token: params.inputToken,
26228
26503
  amount: params.inputAmount,
@@ -26541,6 +26816,11 @@ var SwapService = class {
26541
26816
  * Use this after `getStatus` returns `SolverIntentStatusCode.SOLVED (3)` to obtain the
26542
26817
  * destination-chain transaction hash from `packet.dst_tx_hash`.
26543
26818
  *
26819
+ * A single solver fill tx emits multiple relay packets sharing the same `src_tx_hash`. The
26820
+ * user-facing `IntentFilled` delivery is the packet whose payload targets the hub intents
26821
+ * contract; `selectSolvedIntentPacket` disambiguates so the returned `dst_tx_hash` is the
26822
+ * destination delivery tx rather than an internal hop.
26823
+ *
26544
26824
  * @param chainId - The destination spoke chain key (where output tokens are delivered).
26545
26825
  * @param fillTxHash - The solver's fill transaction hash, obtained from `getStatus.fill_tx_hash`.
26546
26826
  * @param timeout - Poll timeout in milliseconds. Defaults to `DEFAULT_RELAY_TX_TIMEOUT` (120 s).
@@ -26556,7 +26836,8 @@ var SwapService = class {
26556
26836
  intentRelayChainId: getIntentRelayChainId(chainId).toString(),
26557
26837
  srcTxHash: fillTxHash,
26558
26838
  timeout,
26559
- apiUrl: this.relayerApiEndpoint
26839
+ apiUrl: this.relayerApiEndpoint,
26840
+ selectPacket: (packets) => selectSolvedIntentPacket(packets, this.solver.intentsContract)
26560
26841
  });
26561
26842
  }
26562
26843
  /**
@@ -29081,10 +29362,10 @@ var BridgeService = class {
29081
29362
  * @returns Fee amount to be deducted, in the same units as `inputAmount`.
29082
29363
  */
29083
29364
  getFee(inputAmount) {
29084
- if (!this.config.bridge.partnerFee) {
29365
+ if (!this.config.bridgePartnerFee) {
29085
29366
  return 0n;
29086
29367
  }
29087
- return calculateFeeAmount(inputAmount, this.config.bridge.partnerFee);
29368
+ return calculateFeeAmount(inputAmount, this.config.bridgePartnerFee);
29088
29369
  }
29089
29370
  /**
29090
29371
  * Checks whether the caller has sufficient token allowance to execute the bridge.
@@ -29361,7 +29642,7 @@ var BridgeService = class {
29361
29642
  }
29362
29643
  const hubWallet = await this.hubProvider.getUserHubWalletAddress(walletAddress, params.srcChainKey);
29363
29644
  const effectiveSkipSimulation = skipSimulation || isBitcoinChainKeyType(params.srcChainKey) && this.spoke.bitcoin.walletMode === "USER";
29364
- const data = this.buildBridgeData(params, srcToken, dstToken, this.config.bridge.partnerFee);
29645
+ const data = this.buildBridgeData(params, srcToken, dstToken, this.config.bridgePartnerFee);
29365
29646
  const coreParams = {
29366
29647
  srcChainKey: params.srcChainKey,
29367
29648
  srcAddress: walletAddress,
@@ -35240,7 +35521,7 @@ var MoneyMarketService = class _MoneyMarketService {
35240
35521
  this.config = config;
35241
35522
  this.hubProvider = hubProvider;
35242
35523
  this.spoke = spoke;
35243
- this.partnerFee = config.moneyMarket.partnerFee;
35524
+ this.partnerFee = config.moneyMarketPartnerFee;
35244
35525
  this.relayerApiEndpoint = config.relay.relayerApiEndpoint;
35245
35526
  this.data = new MoneyMarketDataService({ hubProvider, config });
35246
35527
  }
@@ -37013,7 +37294,12 @@ var RecoveryService = class {
37013
37294
  srcChainKey: chainKey,
37014
37295
  field: "chainKey"
37015
37296
  });
37016
- const entries = Object.values(chainConfig.supportedTokens).filter((token) => viem.isAddress(token.hubAsset));
37297
+ const leverageVaultAddresses = new Set(
37298
+ this.config.sodaxConfig.leverageYield.vaults.map((vault) => vault.vault.toLowerCase())
37299
+ );
37300
+ const entries = Object.values(chainConfig.supportedTokens).filter(
37301
+ (token) => viem.isAddress(token.hubAsset) && !leverageVaultAddresses.has(token.hubAsset.toLowerCase())
37302
+ );
37017
37303
  if (entries.length === 0) {
37018
37304
  return { ok: true, value: [] };
37019
37305
  }
@@ -37115,6 +37401,871 @@ var RecoveryService = class {
37115
37401
  }
37116
37402
  };
37117
37403
 
37404
+ // src/leverageYield/errors.ts
37405
+ var leverageYieldInvariant = createInvariant("leverageYield");
37406
+ var LEVERAGE_YIELD_CODES = /* @__PURE__ */ new Set([
37407
+ "VALIDATION_FAILED",
37408
+ "INTENT_CREATION_FAILED",
37409
+ "APPROVE_FAILED",
37410
+ "ALLOWANCE_CHECK_FAILED",
37411
+ "LOOKUP_FAILED",
37412
+ "TX_VERIFICATION_FAILED",
37413
+ "TX_SUBMIT_FAILED",
37414
+ "RELAY_TIMEOUT",
37415
+ "RELAY_FAILED",
37416
+ "EXECUTION_FAILED",
37417
+ "EXTERNAL_API_ERROR",
37418
+ "UNKNOWN"
37419
+ ]);
37420
+ var LEVERAGE_YIELD_POST_EXECUTION_CODES = /* @__PURE__ */ new Set([
37421
+ "EXECUTION_FAILED",
37422
+ "EXTERNAL_API_ERROR",
37423
+ "UNKNOWN"
37424
+ ]);
37425
+ var LEVERAGE_YIELD_SWAP_CODES = /* @__PURE__ */ new Set([
37426
+ "VALIDATION_FAILED",
37427
+ "INTENT_CREATION_FAILED",
37428
+ "TX_VERIFICATION_FAILED",
37429
+ "TX_SUBMIT_FAILED",
37430
+ "RELAY_TIMEOUT",
37431
+ "RELAY_FAILED",
37432
+ "EXECUTION_FAILED",
37433
+ "EXTERNAL_API_ERROR",
37434
+ "UNKNOWN"
37435
+ ]);
37436
+ var isLeverageYieldCreateIntentError = isCodeMember(CREATE_INTENT_CODES);
37437
+ var isLeverageYieldApproveError = isCodeMember(APPROVE_CODES);
37438
+ var isLeverageYieldAllowanceCheckError = isCodeMember(ALLOWANCE_CHECK_CODES);
37439
+ var isLeverageYieldLookupError = isCodeMember(LOOKUP_CODES);
37440
+ var isLeverageYieldPostExecutionError = isCodeMember(
37441
+ LEVERAGE_YIELD_POST_EXECUTION_CODES
37442
+ );
37443
+ var isLeverageYieldSwapError = isCodeMember(LEVERAGE_YIELD_SWAP_CODES);
37444
+ var isLeverageYieldError = isCodeMember(LEVERAGE_YIELD_CODES);
37445
+
37446
+ // src/leverageYield/LeverageYieldService.ts
37447
+ var leverageYieldVaultAbi = viem.parseAbi([
37448
+ "function asset() view returns (address)",
37449
+ "function getPositionDetails() view returns (uint256 collateral, uint256 debt, uint256 ltv, uint256 healthFactor, uint256 idleAsset)",
37450
+ // Used by getApr() — read-only metadata that doesn't change per pass.
37451
+ "function pool() view returns (address)",
37452
+ "function borrowToken() view returns (address)",
37453
+ "function targetLTV() view returns (uint256)"
37454
+ ]);
37455
+ var INTENT_DEADLINE_BUFFER_SECONDS = 5 * 60;
37456
+ var ANY_SOLVER_ADDRESS = "0x0000000000000000000000000000000000000000";
37457
+ var MAX_WITHDRAW_DUST_BUFFER = 1000n;
37458
+ function pctToRay(aprPct) {
37459
+ return BigInt(Math.round(aprPct * 1e9)) * 10n ** 16n;
37460
+ }
37461
+ var DEFILLAMA_FETCH_TIMEOUT_MS = 1e4;
37462
+ var DEFILLAMA_FETCH_MAX_ATTEMPTS = 2;
37463
+ async function fetchWithTimeout(url, timeoutMs) {
37464
+ const controller = new AbortController();
37465
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
37466
+ try {
37467
+ return await fetch(url, { signal: controller.signal });
37468
+ } finally {
37469
+ clearTimeout(timeoutId);
37470
+ }
37471
+ }
37472
+ async function fetchDefillamaApr(poolId) {
37473
+ return retry(async () => {
37474
+ const response = await fetchWithTimeout(`https://yields.llama.fi/chart/${poolId}`, DEFILLAMA_FETCH_TIMEOUT_MS);
37475
+ if (!response.ok) throw new Error(`DefiLlama APR fetch failed: HTTP ${response.status}`);
37476
+ const json = await response.json();
37477
+ const series = json?.data;
37478
+ if (!Array.isArray(series) || series.length === 0) {
37479
+ throw new Error("DefiLlama APR response: empty time series");
37480
+ }
37481
+ const latest = series[series.length - 1]?.apy;
37482
+ if (typeof latest !== "number") throw new Error("DefiLlama APR: latest entry missing numeric apy");
37483
+ return latest;
37484
+ }, DEFILLAMA_FETCH_MAX_ATTEMPTS);
37485
+ }
37486
+ var LeverageYieldService = class {
37487
+ hubProvider;
37488
+ config;
37489
+ spoke;
37490
+ constructor({ hubProvider, config, spoke }) {
37491
+ this.hubProvider = hubProvider;
37492
+ this.config = config;
37493
+ this.spoke = spoke;
37494
+ }
37495
+ // ─── Registry ──────────────────────────────────────────────────────────
37496
+ /** Returns the static registry of known leverage-yield vaults. */
37497
+ listVaults() {
37498
+ return this.config.sodaxConfig.leverageYield.vaults;
37499
+ }
37500
+ /** Looks up a vault by its `name` field. Returns `undefined` when not registered. */
37501
+ getVault(name) {
37502
+ return this.listVaults().find((v) => v.name === name);
37503
+ }
37504
+ /**
37505
+ * Looks up a registered vault by its on-chain proxy address (case-insensitive).
37506
+ * Returns `undefined` when the address isn't in the registry.
37507
+ */
37508
+ getVaultByAddress(address) {
37509
+ const normalized = address.toLowerCase();
37510
+ return this.listVaults().find((v) => v.vault.toLowerCase() === normalized);
37511
+ }
37512
+ /**
37513
+ * Resolves the intent `deadline`: returns the caller-supplied value verbatim, otherwise
37514
+ * derives a default from the hub-chain (Sonic) block timestamp plus
37515
+ * {@link INTENT_DEADLINE_BUFFER_SECONDS}. The deadline is enforced on-chain against the hub
37516
+ * block time, so the default is anchored to that block — never the client clock, which can
37517
+ * drift and produce an already-expired or over-extended deadline.
37518
+ *
37519
+ * Returns a {@link Result}: a `getBlock` RPC outage is a read failure, surfaced as
37520
+ * `LOOKUP_FAILED` (`method: 'resolveDeadline'`) rather than masquerading as an intent-build
37521
+ * failure. The `deposit` / `withdraw` callers forward it verbatim.
37522
+ */
37523
+ async resolveDeadline(deadline, srcChainKey) {
37524
+ if (deadline !== void 0) return { ok: true, value: deadline };
37525
+ try {
37526
+ const block = await this.hubProvider.publicClient.getBlock({
37527
+ includeTransactions: false,
37528
+ blockTag: "latest"
37529
+ });
37530
+ return { ok: true, value: block.timestamp + BigInt(INTENT_DEADLINE_BUFFER_SECONDS) };
37531
+ } catch (error) {
37532
+ return { ok: false, error: lookupFailed("leverageYield", "resolveDeadline", error, { srcChainKey }) };
37533
+ }
37534
+ }
37535
+ /**
37536
+ * Builds the {@link LeverageYieldSwapPayload} for a leverage-yield deposit (any token → lsoda*).
37537
+ * The lsoda* output is delivered to the user's hub wallet on Sonic so a later
37538
+ * {@link LeverageYieldService.withdraw} can swap it back. Spread the result into
37539
+ * {@link LeverageYieldService.vaultSwap}: `vaultSwap({ ...payload, walletProvider })`.
37540
+ * An optional `partnerFee` is forwarded on the payload as the per-intent fee override.
37541
+ *
37542
+ * For `minOutputAmount`, quote via `sodax.swaps.getQuote` with the vault address as the
37543
+ * destination token (`token_dst`) — vault shares are solver-tradeable, so the generic swap
37544
+ * quote applies; then subtract your slippage tolerance.
37545
+ */
37546
+ async deposit(params) {
37547
+ const baseCtx = { srcChainKey: params.srcChainKey, action: "deposit" };
37548
+ try {
37549
+ leverageYieldInvariant(params.inputAmount > 0n, "inputAmount must be greater than 0", {
37550
+ ...baseCtx,
37551
+ field: "inputAmount"
37552
+ });
37553
+ leverageYieldInvariant(params.vault.length > 0, "Vault address is required", { ...baseCtx, field: "vault" });
37554
+ leverageYieldInvariant(params.inputToken.length > 0, "inputToken is required", {
37555
+ ...baseCtx,
37556
+ field: "inputToken"
37557
+ });
37558
+ const hubWallet = await this.hubProvider.getUserHubWalletAddress(params.srcAddress, params.srcChainKey);
37559
+ const deadlineResult = await this.resolveDeadline(params.deadline, params.srcChainKey);
37560
+ if (!deadlineResult.ok) return deadlineResult;
37561
+ const deadline = deadlineResult.value;
37562
+ return {
37563
+ ok: true,
37564
+ value: {
37565
+ params: {
37566
+ inputToken: params.inputToken,
37567
+ outputToken: params.vault,
37568
+ inputAmount: params.inputAmount,
37569
+ minOutputAmount: params.minOutputAmount,
37570
+ deadline,
37571
+ allowPartialFill: false,
37572
+ srcChainKey: params.srcChainKey,
37573
+ dstChainKey: this.hubProvider.chainConfig.chain.key,
37574
+ srcAddress: params.srcAddress,
37575
+ dstAddress: hubWallet,
37576
+ solver: params.solver ?? ANY_SOLVER_ADDRESS,
37577
+ data: "0x"
37578
+ },
37579
+ // Per-intent fee override — only included when the caller supplies one, so the
37580
+ // payload stays free of undefined-valued keys.
37581
+ ...params.partnerFee !== void 0 && { partnerFee: params.partnerFee }
37582
+ }
37583
+ };
37584
+ } catch (error) {
37585
+ if (isLeverageYieldCreateIntentError(error)) return { ok: false, error };
37586
+ return { ok: false, error: intentCreationFailed("leverageYield", error, baseCtx) };
37587
+ }
37588
+ }
37589
+ /**
37590
+ * Builds the {@link LeverageYieldSwapPayload} for a leverage-yield withdraw (lsoda* → any
37591
+ * token). The payload carries `hubWalletSwap: true` — {@link LeverageYieldService.vaultSwap}
37592
+ * then spends the lsoda* held in the user's hub wallet by authorising it via a
37593
+ * `Connection.sendMessage` the user signs on `srcChainKey`. Wrapped in a {@link Result} for
37594
+ * a call shape uniform with {@link LeverageYieldService.deposit}; async because the default
37595
+ * `deadline` is read from the hub block timestamp.
37596
+ *
37597
+ * For `minOutputAmount`, quote via `sodax.swaps.getQuote` with the vault address as the
37598
+ * source token (`token_src`) — vault shares are solver-tradeable, so the generic swap quote
37599
+ * applies; then subtract your slippage tolerance.
37600
+ */
37601
+ async withdraw(params) {
37602
+ const baseCtx = { srcChainKey: params.srcChainKey, action: "withdraw" };
37603
+ try {
37604
+ leverageYieldInvariant(params.inputAmount > 0n, "inputAmount must be greater than 0", {
37605
+ ...baseCtx,
37606
+ field: "inputAmount"
37607
+ });
37608
+ leverageYieldInvariant(params.vault.length > 0, "Vault address is required", { ...baseCtx, field: "vault" });
37609
+ leverageYieldInvariant(params.outputToken.length > 0, "outputToken is required", {
37610
+ ...baseCtx,
37611
+ field: "outputToken"
37612
+ });
37613
+ const deadlineResult = await this.resolveDeadline(params.deadline, params.srcChainKey);
37614
+ if (!deadlineResult.ok) return deadlineResult;
37615
+ const deadline = deadlineResult.value;
37616
+ return {
37617
+ ok: true,
37618
+ value: {
37619
+ params: {
37620
+ inputToken: params.vault,
37621
+ outputToken: params.outputToken,
37622
+ inputAmount: params.inputAmount,
37623
+ minOutputAmount: params.minOutputAmount,
37624
+ deadline,
37625
+ allowPartialFill: false,
37626
+ srcChainKey: params.srcChainKey,
37627
+ dstChainKey: params.dstChainKey,
37628
+ srcAddress: params.srcAddress,
37629
+ dstAddress: params.recipient ?? params.srcAddress,
37630
+ solver: params.solver ?? ANY_SOLVER_ADDRESS,
37631
+ data: "0x"
37632
+ },
37633
+ hubWalletSwap: true
37634
+ }
37635
+ };
37636
+ } catch (error) {
37637
+ if (isLeverageYieldCreateIntentError(error)) return { ok: false, error };
37638
+ return { ok: false, error: intentCreationFailed("leverageYield", error, baseCtx) };
37639
+ }
37640
+ }
37641
+ /**
37642
+ * Creates a vault swap intent on the user's source spoke chain without submitting it to
37643
+ * the solver. Leverage-yield copy of the swap domain's `createIntent`, specialised for
37644
+ * vault flows — duplicated deliberately so the vault-specific execution modifiers
37645
+ * (`hubWalletSwap`, per-intent `partnerFee`) stay off the generic swap surface.
37646
+ *
37647
+ * Use {@link LeverageYieldService.vaultSwap} for the full end-to-end flow
37648
+ * (create → relay → notify solver); use this directly when you need the raw transaction
37649
+ * or drive the relay yourself (e.g. the backend submit-tx path). To complete a manual flow,
37650
+ * relay the returned `relayData` (the shared `relayTxAndWaitPacket` helper) and then call
37651
+ * {@link LeverageYieldService.notifySolver} with the hub-side intent tx hash.
37652
+ *
37653
+ * @param _params - Intent parameters, source chain key, wallet provider (when `raw: false`),
37654
+ * and optional `skipSimulation` / `hubWalletSwap` / `partnerFee`.
37655
+ * @returns A `Result<CreateVaultIntentResult<K, Raw>, LeverageYieldCreateIntentError>`.
37656
+ * On success contains:
37657
+ * - `tx` — chain-specific tx hash (executed) or raw tx data (raw mode).
37658
+ * - `intent` — the fully constructed `Intent` object augmented with `feeAmount`.
37659
+ * - `relayData` — `{ address, payload }` needed to submit the intent to the relayer.
37660
+ *
37661
+ * On failure `result.error` is a SodaxError with `VALIDATION_FAILED` (invariant
37662
+ * precondition), `INTENT_CREATION_FAILED` (spoke-side creation/deposit failed) or
37663
+ * `UNKNOWN` (defensive fallback).
37664
+ */
37665
+ async createVaultIntent(_params) {
37666
+ const { params, skipSimulation, hubWalletSwap, partnerFee = this.config.swapPartnerFee } = _params;
37667
+ const baseCtx = { srcChainKey: params.srcChainKey, dstChainKey: params.dstChainKey };
37668
+ try {
37669
+ leverageYieldInvariant(
37670
+ isUndefinedOrValidWalletProviderForChainKey(params.srcChainKey, _params.walletProvider),
37671
+ `Invalid wallet provider for chain key: ${params.srcChainKey}`,
37672
+ baseCtx
37673
+ );
37674
+ const hubChainKey = this.hubProvider.chainConfig.chain.key;
37675
+ const inputTokenChainKey = hubWalletSwap ? hubChainKey : params.srcChainKey;
37676
+ leverageYieldInvariant(
37677
+ this.config.isValidOriginalAssetAddress(inputTokenChainKey, params.inputToken),
37678
+ `Unsupported spoke chain token (srcChainKey: ${inputTokenChainKey}, inputToken: ${params.inputToken})`,
37679
+ { ...baseCtx, field: "inputToken" }
37680
+ );
37681
+ leverageYieldInvariant(
37682
+ this.config.isValidOriginalAssetAddress(params.dstChainKey, params.outputToken),
37683
+ `Unsupported spoke chain token (params.dstChain: ${params.dstChainKey}, params.outputToken: ${params.outputToken})`,
37684
+ { ...baseCtx, field: "outputToken" }
37685
+ );
37686
+ leverageYieldInvariant(
37687
+ this.config.isValidSpokeChainKey(params.srcChainKey),
37688
+ `Invalid spoke chain (srcChainKey): ${params.srcChainKey}`,
37689
+ { ...baseCtx, field: "srcChainKey" }
37690
+ );
37691
+ leverageYieldInvariant(
37692
+ this.config.isValidSpokeChainKey(params.dstChainKey),
37693
+ `Invalid spoke chain (params.dstChain): ${params.dstChainKey}`,
37694
+ { ...baseCtx, field: "dstChainKey" }
37695
+ );
37696
+ if (isBitcoinChainKey(params.dstChainKey) && params.outputToken === "BTC") {
37697
+ leverageYieldInvariant(
37698
+ params.minOutputAmount >= 546n,
37699
+ `Invalid minOutputAmount (params.minOutputAmount): ${params.minOutputAmount}`,
37700
+ { ...baseCtx, field: "minOutputAmount" }
37701
+ );
37702
+ }
37703
+ const personalAddress = params.srcAddress;
37704
+ let walletAddress = personalAddress;
37705
+ if (isBitcoinChainKeyType(params.srcChainKey) && _params.raw === false) {
37706
+ leverageYieldInvariant(
37707
+ isBitcoinWalletProviderType(_params.walletProvider),
37708
+ `Invalid wallet provider for chain key: ${params.srcChainKey}`,
37709
+ baseCtx
37710
+ );
37711
+ walletAddress = await this.spoke.bitcoin.getEffectiveWalletAddress(personalAddress);
37712
+ await this.spoke.bitcoin.radfi.ensureRadfiAccessToken(_params.walletProvider);
37713
+ }
37714
+ const creatorHubWalletAddress = await this.hubProvider.getUserHubWalletAddress(walletAddress, params.srcChainKey);
37715
+ if (hubWalletSwap) {
37716
+ const [data2, intent2, feeAmount2] = EvmSolverService.constructCreateIntentData(
37717
+ { ...params, srcChainKey: hubChainKey, srcAddress: creatorHubWalletAddress },
37718
+ creatorHubWalletAddress,
37719
+ this.config,
37720
+ partnerFee
37721
+ );
37722
+ const coreSendMessageParams = {
37723
+ srcChainKey: params.srcChainKey,
37724
+ // Personal address — NOT the resolved trading `walletAddress`. SpokeService.sendMessage
37725
+ // re-resolves the effective (Bitcoin trading) address itself; passing the already-resolved
37726
+ // trading address here would double-resolve it (getTradingWallet(tradingAddress) →
37727
+ // "Trading wallet not found"). The trading address is used only for the hub-wallet
37728
+ // derivation above (creatorHubWalletAddress). Mirrors MoneyMarketService borrow/withdraw.
37729
+ srcAddress: personalAddress,
37730
+ dstChainKey: hubChainKey,
37731
+ dstAddress: creatorHubWalletAddress,
37732
+ payload: data2,
37733
+ skipSimulation
37734
+ };
37735
+ const txResult2 = await this.spoke.sendMessage(
37736
+ _params.raw ? { ...coreSendMessageParams, raw: true } : {
37737
+ ...coreSendMessageParams,
37738
+ raw: false,
37739
+ walletProvider: _params.walletProvider
37740
+ }
37741
+ );
37742
+ if (!txResult2.ok) {
37743
+ if (isLeverageYieldCreateIntentError(txResult2.error)) {
37744
+ return { ok: false, error: txResult2.error };
37745
+ }
37746
+ return { ok: false, error: intentCreationFailed("leverageYield", txResult2.error, baseCtx) };
37747
+ }
37748
+ return {
37749
+ ok: true,
37750
+ value: {
37751
+ tx: txResult2.value,
37752
+ intent: { ...intent2, feeAmount: feeAmount2 },
37753
+ relayData: { address: creatorHubWalletAddress, payload: data2 }
37754
+ }
37755
+ };
37756
+ }
37757
+ if (isHubChainKeyType(params.srcChainKey) && isSonicChainKeyType(params.srcChainKey)) {
37758
+ const coreSonicParams = {
37759
+ createIntentParams: params,
37760
+ creatorHubWalletAddress,
37761
+ solverConfig: this.config.solver,
37762
+ fee: partnerFee,
37763
+ hubProvider: this.hubProvider
37764
+ };
37765
+ const [txResult2, intent2, feeAmount2, data2] = await SonicSpokeService.createSwapIntent(
37766
+ _params.raw ? { ...coreSonicParams, raw: true } : {
37767
+ ...coreSonicParams,
37768
+ raw: false,
37769
+ walletProvider: _params.walletProvider
37770
+ }
37771
+ );
37772
+ return {
37773
+ ok: true,
37774
+ value: {
37775
+ tx: txResult2,
37776
+ intent: { ...intent2, feeAmount: feeAmount2 },
37777
+ relayData: { address: intent2.creator, payload: data2 }
37778
+ }
37779
+ };
37780
+ }
37781
+ const [data, intent, feeAmount] = EvmSolverService.constructCreateIntentData(
37782
+ {
37783
+ ...params,
37784
+ srcAddress: walletAddress
37785
+ },
37786
+ creatorHubWalletAddress,
37787
+ this.config,
37788
+ partnerFee
37789
+ );
37790
+ const coreDepositParams = {
37791
+ srcChainKey: params.srcChainKey,
37792
+ srcAddress: walletAddress,
37793
+ to: creatorHubWalletAddress,
37794
+ token: params.inputToken,
37795
+ amount: params.inputAmount,
37796
+ data,
37797
+ skipSimulation
37798
+ };
37799
+ const txResult = await this.spoke.deposit(
37800
+ _params.raw ? {
37801
+ ...coreDepositParams,
37802
+ raw: true
37803
+ } : {
37804
+ ...coreDepositParams,
37805
+ raw: false,
37806
+ walletProvider: _params.walletProvider
37807
+ }
37808
+ );
37809
+ if (!txResult.ok) {
37810
+ if (isLeverageYieldCreateIntentError(txResult.error)) {
37811
+ return { ok: false, error: txResult.error };
37812
+ }
37813
+ return {
37814
+ ok: false,
37815
+ error: intentCreationFailed("leverageYield", txResult.error, baseCtx)
37816
+ };
37817
+ }
37818
+ return {
37819
+ ok: true,
37820
+ value: {
37821
+ tx: txResult.value,
37822
+ intent: { ...intent, feeAmount },
37823
+ relayData: { address: intent.creator, payload: data }
37824
+ }
37825
+ };
37826
+ } catch (error) {
37827
+ if (isLeverageYieldCreateIntentError(error)) return { ok: false, error };
37828
+ return {
37829
+ ok: false,
37830
+ error: intentCreationFailed("leverageYield", error, baseCtx)
37831
+ };
37832
+ }
37833
+ }
37834
+ /**
37835
+ * Executes a full end-to-end leverage-yield vault swap (deposit or withdraw).
37836
+ * Leverage-yield copy of the swap domain's `swap()` orchestrator:
37837
+ * 1. Calls {@link LeverageYieldService.createVaultIntent} to submit the intent
37838
+ * transaction on the source spoke chain.
37839
+ * 2. Verifies the spoke transaction landed on-chain.
37840
+ * 3. For non-hub source chains: submits the spoke tx to the relayer and waits for the
37841
+ * relay packet to land on the hub (Sonic). Skipped when `srcChainKey` is the hub.
37842
+ * 4. Notifies the solver, triggering it to fill the intent.
37843
+ *
37844
+ * Spread a {@link LeverageYieldSwapPayload} from `deposit` / `withdraw` into this method
37845
+ * alongside the wallet provider: `vaultSwap({ ...payload, walletProvider })`.
37846
+ *
37847
+ * @returns A `Result<VaultSwapResponse, LeverageYieldSwapError>`. On success:
37848
+ * - `solverExecutionResponse` — solver acknowledgement (`{ answer: 'OK', intent_hash }`).
37849
+ * - `intent` — the on-chain intent object that was created.
37850
+ * - `intentDeliveryInfo` — source/destination chain keys, tx hashes, and user addresses.
37851
+ *
37852
+ * On failure `result.error` carries one of the create-intent codes plus
37853
+ * `TX_VERIFICATION_FAILED`, `TX_SUBMIT_FAILED`, `RELAY_TIMEOUT`, `RELAY_FAILED`,
37854
+ * `EXECUTION_FAILED`, `EXTERNAL_API_ERROR` or `UNKNOWN`.
37855
+ */
37856
+ async vaultSwap(_params) {
37857
+ const { params } = _params;
37858
+ const srcChainKey = params.srcChainKey;
37859
+ const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "vaultSwap" };
37860
+ try {
37861
+ const timeout = _params.timeout;
37862
+ const createIntentResult = await this.createVaultIntent(_params);
37863
+ if (!createIntentResult.ok) {
37864
+ return { ok: false, error: createIntentResult.error };
37865
+ }
37866
+ const { tx: spokeTxHash, intent, relayData } = createIntentResult.value;
37867
+ const verifyTxHashResult = await this.spoke.verifyTxHash({
37868
+ txHash: spokeTxHash,
37869
+ chainKey: srcChainKey
37870
+ });
37871
+ if (!verifyTxHashResult.ok) {
37872
+ return {
37873
+ ok: false,
37874
+ error: verifyFailed("leverageYield", verifyTxHashResult.error, baseCtx)
37875
+ };
37876
+ }
37877
+ let dstIntentTxHash;
37878
+ if (isHubChainKeyType(srcChainKey)) {
37879
+ dstIntentTxHash = spokeTxHash;
37880
+ } else {
37881
+ const packet = await relayTxAndWaitPacket({
37882
+ srcTxHash: spokeTxHash,
37883
+ data: relayData,
37884
+ chainKey: srcChainKey,
37885
+ relayerApiEndpoint: this.config.relay.relayerApiEndpoint,
37886
+ timeout
37887
+ });
37888
+ if (!packet.ok) {
37889
+ return {
37890
+ ok: false,
37891
+ error: mapRelayFailure(packet.error, { feature: "leverageYield", ...baseCtx })
37892
+ };
37893
+ }
37894
+ dstIntentTxHash = packet.value.dst_tx_hash;
37895
+ }
37896
+ const postExecResult = await this.notifySolver({
37897
+ intent_tx_hash: dstIntentTxHash
37898
+ });
37899
+ if (!postExecResult.ok) {
37900
+ return { ok: false, error: postExecResult.error };
37901
+ }
37902
+ return {
37903
+ ok: true,
37904
+ value: {
37905
+ solverExecutionResponse: postExecResult.value,
37906
+ intent,
37907
+ intentDeliveryInfo: {
37908
+ srcChainKey,
37909
+ srcTxHash: spokeTxHash,
37910
+ srcAddress: params.srcAddress,
37911
+ dstChainKey: params.dstChainKey,
37912
+ dstTxHash: dstIntentTxHash,
37913
+ dstAddress: params.dstAddress
37914
+ }
37915
+ }
37916
+ };
37917
+ } catch (error) {
37918
+ if (isLeverageYieldSwapError(error)) return { ok: false, error };
37919
+ return {
37920
+ ok: false,
37921
+ error: unknownFailed("leverageYield", error, baseCtx)
37922
+ };
37923
+ }
37924
+ }
37925
+ /**
37926
+ * Notifies the solver that the vault intent landed on the hub, triggering it to fill.
37927
+ * Leverage-yield copy of the swap domain's `postExecution` — emits only
37928
+ * `EXECUTION_FAILED` / `EXTERNAL_API_ERROR` / `UNKNOWN` (relay/verify codes appear only
37929
+ * on {@link LeverageYieldService.vaultSwap}, which owns the verify + relay steps).
37930
+ *
37931
+ * Called automatically by {@link LeverageYieldService.vaultSwap} after the relay packet
37932
+ * lands on the hub. Public so callers who created the intent via
37933
+ * {@link LeverageYieldService.createVaultIntent} and relayed it themselves can finish the
37934
+ * flow manually.
37935
+ *
37936
+ * @param request - `{ intent_tx_hash }` — the hub-chain (Sonic) tx hash where the intent
37937
+ * was registered (the relay packet's `dst_tx_hash`, or the spoke tx hash for hub-sourced
37938
+ * intents).
37939
+ */
37940
+ async notifySolver(request) {
37941
+ try {
37942
+ const result = await SolverApiService.postExecution(request, this.config.solver, this.config.logger);
37943
+ if (result.ok) return result;
37944
+ const detail = result.error?.detail ?? {
37945
+ code: -999,
37946
+ // SolverIntentErrorCode.UNKNOWN
37947
+ message: "Solver returned malformed error response"
37948
+ };
37949
+ return {
37950
+ ok: false,
37951
+ error: new SodaxError("EXTERNAL_API_ERROR", detail.message, {
37952
+ feature: "leverageYield",
37953
+ context: {
37954
+ phase: "postExecution",
37955
+ api: "solver",
37956
+ solverCode: detail.code,
37957
+ solverDetail: detail
37958
+ }
37959
+ })
37960
+ };
37961
+ } catch (error) {
37962
+ if (isLeverageYieldPostExecutionError(error)) return { ok: false, error };
37963
+ return { ok: false, error: executionFailed("leverageYield", error, { phase: "postExecution" }) };
37964
+ }
37965
+ }
37966
+ /**
37967
+ * Approves the vault's underlying asset to the leverage vault on Sonic. For callers
37968
+ * interacting with the vault directly on the hub — the swap-style {@link
37969
+ * LeverageYieldService.deposit} flow handles its own approvals.
37970
+ */
37971
+ async approve(params) {
37972
+ const baseCtx = { action: "approve" };
37973
+ try {
37974
+ leverageYieldInvariant(params.amount > 0n, "Amount must be greater than 0", { ...baseCtx, field: "amount" });
37975
+ leverageYieldInvariant(params.vault.length > 0, "Vault address is required", { ...baseCtx, field: "vault" });
37976
+ const assetResult = await this.getAsset(params.vault);
37977
+ if (!assetResult.ok) {
37978
+ return { ok: false, error: approveFailed("leverageYield", assetResult.error, baseCtx) };
37979
+ }
37980
+ const from = await params.walletProvider.getWalletAddress();
37981
+ const baseApprove = {
37982
+ token: assetResult.value,
37983
+ amount: params.amount,
37984
+ from,
37985
+ spender: params.vault
37986
+ };
37987
+ if (params.raw) {
37988
+ const tx2 = await Erc20Service.approve({ ...baseApprove, raw: true });
37989
+ return { ok: true, value: tx2 };
37990
+ }
37991
+ const tx = await Erc20Service.approve({
37992
+ ...baseApprove,
37993
+ raw: false,
37994
+ walletProvider: params.walletProvider
37995
+ });
37996
+ return { ok: true, value: tx };
37997
+ } catch (error) {
37998
+ if (isLeverageYieldApproveError(error)) return { ok: false, error };
37999
+ return { ok: false, error: approveFailed("leverageYield", error, baseCtx) };
38000
+ }
38001
+ }
38002
+ /**
38003
+ * Reads on-chain allowance of the vault's underlying asset for `owner → vault`. Returns
38004
+ * `true` when the allowance covers `amount`. Use before a direct
38005
+ * {@link LeverageYieldService.deposit}.
38006
+ */
38007
+ async isAllowanceValid(params) {
38008
+ const baseCtx = { action: "allowanceCheck" };
38009
+ try {
38010
+ leverageYieldInvariant(params.amount > 0n, "Amount must be greater than 0", { ...baseCtx, field: "amount" });
38011
+ const assetResult = await this.getAsset(params.vault);
38012
+ if (!assetResult.ok) {
38013
+ return { ok: false, error: allowanceCheckFailed("leverageYield", assetResult.error, baseCtx) };
38014
+ }
38015
+ const allowance = await this.hubProvider.publicClient.readContract({
38016
+ address: assetResult.value,
38017
+ abi: viem.erc20Abi,
38018
+ functionName: "allowance",
38019
+ args: [params.owner, params.vault]
38020
+ });
38021
+ return { ok: true, value: allowance >= params.amount };
38022
+ } catch (error) {
38023
+ if (isLeverageYieldAllowanceCheckError(error)) return { ok: false, error };
38024
+ return { ok: false, error: allowanceCheckFailed("leverageYield", error, baseCtx) };
38025
+ }
38026
+ }
38027
+ // ─── Reads ──────────────────────────────────────────────────────────────
38028
+ /** ERC-4626 `asset()` of the vault — the sodaWEETH-style underlying. */
38029
+ async getAsset(vault) {
38030
+ try {
38031
+ const value = await this.hubProvider.publicClient.readContract({
38032
+ address: vault,
38033
+ abi: leverageYieldVaultAbi,
38034
+ functionName: "asset"
38035
+ });
38036
+ return { ok: true, value };
38037
+ } catch (error) {
38038
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
38039
+ return { ok: false, error: lookupFailed("leverageYield", "getAsset", error) };
38040
+ }
38041
+ }
38042
+ /** Reads the vault's leveraged position snapshot via the non-standard `getPositionDetails`. */
38043
+ async getPosition(vault) {
38044
+ try {
38045
+ const [collateral, debt, ltv, healthFactor, idleAsset] = await this.hubProvider.publicClient.readContract({
38046
+ address: vault,
38047
+ abi: leverageYieldVaultAbi,
38048
+ functionName: "getPositionDetails"
38049
+ });
38050
+ return { ok: true, value: { collateral, debt, ltv, healthFactor, idleAsset } };
38051
+ } catch (error) {
38052
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
38053
+ return { ok: false, error: lookupFailed("leverageYield", "getPosition", error) };
38054
+ }
38055
+ }
38056
+ /**
38057
+ * Computes the steady-state APR of a leverage-yield vault from the AAVE supply/borrow
38058
+ * rates of its asset and borrowToken, scaled by the vault's target leverage. Matches the
38059
+ * convention used by leveraged-LSD vaults (Origami, Gearbox, etc.) — assumes constant
38060
+ * LTV at `targetLTV` and constant AAVE rates.
38061
+ *
38062
+ * Returns raw fields in RAY (1e27, AAVE's native rate scale) plus the leverage multiplier
38063
+ * in WAD (1e18). See {@link LeverageYieldApr} for the formula and caveats.
38064
+ */
38065
+ async getApr(vault) {
38066
+ try {
38067
+ const [pool, asset, borrowToken, targetLtvBps] = await Promise.all([
38068
+ this.hubProvider.publicClient.readContract({
38069
+ address: vault,
38070
+ abi: leverageYieldVaultAbi,
38071
+ functionName: "pool"
38072
+ }),
38073
+ this.hubProvider.publicClient.readContract({
38074
+ address: vault,
38075
+ abi: leverageYieldVaultAbi,
38076
+ functionName: "asset"
38077
+ }),
38078
+ this.hubProvider.publicClient.readContract({
38079
+ address: vault,
38080
+ abi: leverageYieldVaultAbi,
38081
+ functionName: "borrowToken"
38082
+ }),
38083
+ this.hubProvider.publicClient.readContract({
38084
+ address: vault,
38085
+ abi: leverageYieldVaultAbi,
38086
+ functionName: "targetLTV"
38087
+ })
38088
+ ]);
38089
+ const [assetReserve, borrowReserve] = await Promise.all([
38090
+ this.hubProvider.publicClient.readContract({
38091
+ address: pool,
38092
+ abi: poolAbi,
38093
+ functionName: "getReserveData",
38094
+ args: [asset]
38095
+ }),
38096
+ this.hubProvider.publicClient.readContract({
38097
+ address: pool,
38098
+ abi: poolAbi,
38099
+ functionName: "getReserveData",
38100
+ args: [borrowToken]
38101
+ })
38102
+ ]);
38103
+ const supplyAprRay = assetReserve.currentLiquidityRate;
38104
+ const borrowAprRay = borrowReserve.currentVariableBorrowRate;
38105
+ const BPS = 10000n;
38106
+ const WAD2 = 1000000000000000000n;
38107
+ leverageYieldInvariant(targetLtvBps < BPS, `targetLTV (${targetLtvBps}) must be < 100% (10_000 bps)`, {
38108
+ method: "getApr",
38109
+ field: "targetLtvBps"
38110
+ });
38111
+ const leverageMultiplierWad = targetLtvBps * WAD2 / (BPS - targetLtvBps);
38112
+ const spreadRay = supplyAprRay - borrowAprRay;
38113
+ const netAprRay = supplyAprRay + spreadRay * leverageMultiplierWad / WAD2;
38114
+ return {
38115
+ ok: true,
38116
+ value: { supplyAprRay, borrowAprRay, targetLtvBps, leverageMultiplierWad, netAprRay }
38117
+ };
38118
+ } catch (error) {
38119
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
38120
+ return { ok: false, error: lookupFailed("leverageYield", "getApr", error) };
38121
+ }
38122
+ }
38123
+ /**
38124
+ * Off-chain LSD staking-APR for the vault's underlying asset. Looks the vault up in the
38125
+ * registry, hits DefiLlama's per-pool chart endpoint for the configured `poolId`, and on
38126
+ * any fetch failure returns the registry's hardcoded `fallbackAprPct` with `stale: true`.
38127
+ *
38128
+ * Always resolves to `{ ok: true, ... }` for a known vault — the fallback path replaces
38129
+ * the error, since a missing LSD APR shouldn't break the parent call. Returns
38130
+ * `{ aprRay: 0n, stale: true, label: 'no LSD source' }` for vaults without an
38131
+ * `lsdSource` configured (non-LSD strategies); callers can treat that as "skip LSD".
38132
+ */
38133
+ async getLsdApr(vault) {
38134
+ try {
38135
+ const cfg = this.getVaultByAddress(vault);
38136
+ const source = cfg?.lsdSource;
38137
+ if (!source) {
38138
+ return { ok: true, value: { aprRay: 0n, label: "no LSD source", stale: true } };
38139
+ }
38140
+ try {
38141
+ const aprPct = await fetchDefillamaApr(source.poolId);
38142
+ return { ok: true, value: { aprRay: pctToRay(aprPct), label: source.label, stale: false } };
38143
+ } catch (fetchError) {
38144
+ this.config.logger.warn("[leverageYield] DefiLlama APR fetch failed; using fallbackAprPct", {
38145
+ vault,
38146
+ poolId: source.poolId,
38147
+ fallbackAprPct: source.fallbackAprPct,
38148
+ error: fetchError instanceof Error ? fetchError.message : String(fetchError)
38149
+ });
38150
+ return {
38151
+ ok: true,
38152
+ value: { aprRay: pctToRay(source.fallbackAprPct), label: `${source.label} (fallback)`, stale: true }
38153
+ };
38154
+ }
38155
+ } catch (error) {
38156
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
38157
+ return { ok: false, error: lookupFailed("leverageYield", "getLsdApr", error) };
38158
+ }
38159
+ }
38160
+ /**
38161
+ * Combined view of {@link getApr} + {@link getLsdApr}: re-applies the vault's leverage
38162
+ * formula with the LSD's native staking yield folded into the supply side, exposing the
38163
+ * **effective** net APR that LSD-backed strategies actually earn. The AAVE-only
38164
+ * `netAprRay` is preserved on the return value for callers who want to display both.
38165
+ *
38166
+ * effectiveSupply = supplyAprRay + lsdApr.aprRay
38167
+ * effectiveNet = effectiveSupply + leverage × (effectiveSupply − borrowAprRay)
38168
+ *
38169
+ * Fetches AAVE rates and the LSD APR in parallel for one round-trip's worth of latency.
38170
+ */
38171
+ async getEffectiveApr(vault) {
38172
+ try {
38173
+ const [aprResult, lsdResult] = await Promise.all([this.getApr(vault), this.getLsdApr(vault)]);
38174
+ if (!aprResult.ok) return aprResult;
38175
+ if (!lsdResult.ok) return lsdResult;
38176
+ const apr = aprResult.value;
38177
+ const lsd = lsdResult.value;
38178
+ const effectiveSupplyAprRay = apr.supplyAprRay + lsd.aprRay;
38179
+ const spreadRay = effectiveSupplyAprRay - apr.borrowAprRay;
38180
+ const WAD2 = 1000000000000000000n;
38181
+ const effectiveNetAprRay = effectiveSupplyAprRay + spreadRay * apr.leverageMultiplierWad / WAD2;
38182
+ return {
38183
+ ok: true,
38184
+ value: { ...apr, lsdApr: lsd, effectiveSupplyAprRay, effectiveNetAprRay }
38185
+ };
38186
+ } catch (error) {
38187
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
38188
+ return { ok: false, error: lookupFailed("leverageYield", "getEffectiveApr", error) };
38189
+ }
38190
+ }
38191
+ /** Synchronously withdrawable assets for `owner` (clamped against leverage HF floor). */
38192
+ async getMaxWithdraw(vault, owner) {
38193
+ const inner = await Erc4626Service.getMaxWithdraw(vault, owner, this.hubProvider.publicClient);
38194
+ if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "getMaxWithdraw", inner.error) };
38195
+ return { ok: true, value: inner.value };
38196
+ }
38197
+ /** Total underlying assets currently held by the vault (vault-asset units, 18 decimals) — TVL. */
38198
+ async getTotalAssets(vault) {
38199
+ const inner = await Erc4626Service.getTotalAssets(vault, this.hubProvider.publicClient);
38200
+ if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "getTotalAssets", inner.error) };
38201
+ return { ok: true, value: inner.value };
38202
+ }
38203
+ /** Shares minted for a given asset deposit. */
38204
+ async previewDeposit(vault, assets) {
38205
+ const inner = await Erc4626Service.previewDeposit(vault, assets, this.hubProvider.publicClient);
38206
+ if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "previewDeposit", inner.error) };
38207
+ return { ok: true, value: inner.value };
38208
+ }
38209
+ /** Shares burned for a given asset withdrawal. */
38210
+ async previewWithdraw(vault, assets) {
38211
+ const inner = await Erc4626Service.previewWithdraw(vault, assets, this.hubProvider.publicClient);
38212
+ if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "previewWithdraw", inner.error) };
38213
+ return { ok: true, value: inner.value };
38214
+ }
38215
+ /** Assets received for a given share redemption. */
38216
+ async previewRedeem(vault, shares) {
38217
+ const inner = await Erc4626Service.previewRedeem(vault, shares, this.hubProvider.publicClient);
38218
+ if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "previewRedeem", inner.error) };
38219
+ return { ok: true, value: inner.value };
38220
+ }
38221
+ /** Vault shares held by `owner`. */
38222
+ async getShareBalance(vault, owner) {
38223
+ try {
38224
+ const value = await this.hubProvider.publicClient.readContract({
38225
+ address: vault,
38226
+ abi: viem.erc20Abi,
38227
+ functionName: "balanceOf",
38228
+ args: [owner]
38229
+ });
38230
+ return { ok: true, value };
38231
+ } catch (error) {
38232
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
38233
+ return { ok: false, error: lookupFailed("leverageYield", "getShareBalance", error) };
38234
+ }
38235
+ }
38236
+ /**
38237
+ * Convenience: resolves the user's hub wallet from `(srcChainKey, srcAddress)` and
38238
+ * returns its on-chain `maxWithdraw`, less {@link MAX_WITHDRAW_DUST_BUFFER}. The trim
38239
+ * keeps the value safe for an asset-denominated ERC-4626 `withdraw` — the raw
38240
+ * `maxWithdraw` can trip the round-up that asks for one more share than the user holds.
38241
+ */
38242
+ async getMaxWithdrawForUser(vault, srcChainKey, srcAddress) {
38243
+ try {
38244
+ const hubWallet = await this.hubProvider.getUserHubWalletAddress(srcAddress, srcChainKey);
38245
+ const maxWithdrawResult = await this.getMaxWithdraw(vault, hubWallet);
38246
+ if (!maxWithdrawResult.ok) return maxWithdrawResult;
38247
+ const buffered = maxWithdrawResult.value > MAX_WITHDRAW_DUST_BUFFER ? maxWithdrawResult.value - MAX_WITHDRAW_DUST_BUFFER : 0n;
38248
+ return { ok: true, value: buffered };
38249
+ } catch (error) {
38250
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
38251
+ return { ok: false, error: lookupFailed("leverageYield", "getMaxWithdrawForUser", error, { srcChainKey }) };
38252
+ }
38253
+ }
38254
+ /**
38255
+ * Convenience: resolves the user's hub wallet from `(srcChainKey, srcAddress)` and
38256
+ * returns its on-chain share balance.
38257
+ */
38258
+ async getShareBalanceForUser(vault, srcChainKey, srcAddress) {
38259
+ try {
38260
+ const hubWallet = await this.hubProvider.getUserHubWalletAddress(srcAddress, srcChainKey);
38261
+ return await this.getShareBalance(vault, hubWallet);
38262
+ } catch (error) {
38263
+ if (isLeverageYieldLookupError(error)) return { ok: false, error };
38264
+ return { ok: false, error: lookupFailed("leverageYield", "getShareBalanceForUser", error, { srcChainKey }) };
38265
+ }
38266
+ }
38267
+ };
38268
+
37118
38269
  // src/shared/entities/Sodax.ts
37119
38270
  var Sodax = class {
37120
38271
  instanceConfig;
@@ -37136,17 +38287,26 @@ var Sodax = class {
37136
38287
  // Recovery service for withdrawing stuck hub-wallet assets back to a spoke chain
37137
38288
  dex;
37138
38289
  // Dex service enabling DEX operations
38290
+ leverageYield;
38291
+ // Leverage-yield service: cross-chain deposits / withdrawals into ERC-4626 leverage vaults on Sonic
37139
38292
  config;
37140
38293
  // Config service enabling configuration data fetching from the backend API or fallbacking to default values
37141
38294
  hubProvider;
37142
38295
  // hub provider for the hub chain (e.g. Sonic mainnet)
37143
38296
  spoke;
37144
38297
  // spoke service enabling spoke chain operations
37145
- constructor(config) {
37146
- const logger = resolveLogger(config?.logger);
37147
- this.instanceConfig = config ? mergeSodaxConfig(sodaxConfig, config) : sodaxConfig;
38298
+ constructor(options) {
38299
+ const logger = resolveLogger(options?.logger);
38300
+ const fee = options?.fee;
38301
+ this.instanceConfig = options ? mergeSodaxConfig(sodaxConfig, options) : sodaxConfig;
37148
38302
  this.backendApi = new BackendApiService(this.instanceConfig.api, logger);
37149
- this.config = new ConfigService({ api: this.backendApi, config: this.instanceConfig, userConfig: config, logger });
38303
+ this.config = new ConfigService({
38304
+ api: this.backendApi,
38305
+ config: this.instanceConfig,
38306
+ userConfig: options,
38307
+ logger,
38308
+ fee
38309
+ });
37150
38310
  this.hubProvider = new EvmHubProvider({ config: this.config });
37151
38311
  this.spoke = new SpokeService({ config: this.config, hubProvider: this.hubProvider });
37152
38312
  this.swaps = new SwapService({
@@ -37181,6 +38341,11 @@ var Sodax = class {
37181
38341
  config: this.config,
37182
38342
  spoke: this.spoke
37183
38343
  });
38344
+ this.leverageYield = new LeverageYieldService({
38345
+ hubProvider: this.hubProvider,
38346
+ config: this.config,
38347
+ spoke: this.spoke
38348
+ });
37184
38349
  }
37185
38350
  /**
37186
38351
  * Initializes the Sodax instance with dynamic configuration.
@@ -37289,8 +38454,11 @@ exports.IntentsAbi = IntentsAbi;
37289
38454
  exports.LOOKUP_CODES = LOOKUP_CODES;
37290
38455
  exports.LTV_PRECISION = LTV_PRECISION;
37291
38456
  exports.LendingPoolService = LendingPoolService;
38457
+ exports.LeverageYieldService = LeverageYieldService;
37292
38458
  exports.LockupMultiplier = LockupMultiplier;
37293
38459
  exports.LockupPeriod = LockupPeriod;
38460
+ exports.LsodaSymbols = LsodaSymbols;
38461
+ exports.LsodaTokens = LsodaTokens;
37294
38462
  exports.MAX_UINT256 = MAX_UINT256;
37295
38463
  exports.MigrationService = MigrationService;
37296
38464
  exports.MintPositionEventAbi = MintPositionEventAbi;
@@ -37433,6 +38601,7 @@ exports.getReserveNormalizedIncome = getReserveNormalizedIncome;
37433
38601
  exports.getReservesEModes = getReservesEModes;
37434
38602
  exports.getSolanaAddressBytes = getSolanaAddressBytes;
37435
38603
  exports.getSolverConfig = getSolverConfig;
38604
+ exports.getStagingSolverTokens = getStagingSolverTokens;
37436
38605
  exports.getSupportedSolverTokens = getSupportedSolverTokens;
37437
38606
  exports.getTransactionPackets = getTransactionPackets;
37438
38607
  exports.getbnUSDToken = getbnUSDToken;
@@ -37475,6 +38644,13 @@ exports.isInjectiveChainKeyType = isInjectiveChainKeyType;
37475
38644
  exports.isJsonRpcPayloadResponse = isJsonRpcPayloadResponse;
37476
38645
  exports.isLegacybnUSDChainId = isLegacybnUSDChainId;
37477
38646
  exports.isLegacybnUSDToken = isLegacybnUSDToken;
38647
+ exports.isLeverageYieldAllowanceCheckError = isLeverageYieldAllowanceCheckError;
38648
+ exports.isLeverageYieldApproveError = isLeverageYieldApproveError;
38649
+ exports.isLeverageYieldCreateIntentError = isLeverageYieldCreateIntentError;
38650
+ exports.isLeverageYieldError = isLeverageYieldError;
38651
+ exports.isLeverageYieldLookupError = isLeverageYieldLookupError;
38652
+ exports.isLeverageYieldPostExecutionError = isLeverageYieldPostExecutionError;
38653
+ exports.isLeverageYieldSwapError = isLeverageYieldSwapError;
37478
38654
  exports.isMigrateOrchestrationError = isMigrateOrchestrationError;
37479
38655
  exports.isMigrationAllowanceCheckError = isMigrationAllowanceCheckError;
37480
38656
  exports.isMigrationApproveError = isMigrationApproveError;
@@ -37541,6 +38717,9 @@ exports.isUndefinedOrValidWalletProviderForChainKey = isUndefinedOrValidWalletPr
37541
38717
  exports.isUnifiedBnUSDMigrateParams = isUnifiedBnUSDMigrateParams;
37542
38718
  exports.isValidWalletProviderForChainKey = isValidWalletProviderForChainKey;
37543
38719
  exports.kaiaSupportedTokens = kaiaSupportedTokens;
38720
+ exports.leverageYieldConfig = leverageYieldConfig;
38721
+ exports.leverageYieldInvariant = leverageYieldInvariant;
38722
+ exports.leverageYieldVaults = leverageYieldVaults;
37544
38723
  exports.lightlinkSupportedTokens = lightlinkSupportedTokens;
37545
38724
  exports.lookupFailed = lookupFailed;
37546
38725
  exports.mapRelayFailure = mapRelayFailure;
@@ -37600,6 +38779,7 @@ exports.spokeAssetManagerAbi = spokeAssetManagerAbi;
37600
38779
  exports.spokeChainConfig = spokeChainConfig;
37601
38780
  exports.spokeChainKeysSet = spokeChainKeysSet;
37602
38781
  exports.stacksSupportedTokens = stacksSupportedTokens;
38782
+ exports.stagingSwapSupportedTokens = stagingSwapSupportedTokens;
37603
38783
  exports.stakedSodaAbi = stakedSodaAbi;
37604
38784
  exports.stakingInvariant = stakingInvariant;
37605
38785
  exports.stakingRouterAbi = stakingRouterAbi;