wayfinder-paths 0.1.22__py3-none-any.whl → 0.1.24__py3-none-any.whl

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.

Potentially problematic release.


This version of wayfinder-paths might be problematic. Click here for more details.

Files changed (156) hide show
  1. wayfinder_paths/__init__.py +0 -4
  2. wayfinder_paths/adapters/balance_adapter/README.md +0 -1
  3. wayfinder_paths/adapters/balance_adapter/adapter.py +313 -167
  4. wayfinder_paths/adapters/balance_adapter/manifest.yaml +8 -0
  5. wayfinder_paths/adapters/balance_adapter/test_adapter.py +41 -124
  6. wayfinder_paths/adapters/boros_adapter/__init__.py +17 -0
  7. wayfinder_paths/adapters/boros_adapter/adapter.py +1574 -0
  8. wayfinder_paths/adapters/boros_adapter/client.py +476 -0
  9. wayfinder_paths/adapters/boros_adapter/manifest.yaml +10 -0
  10. wayfinder_paths/adapters/boros_adapter/parsers.py +88 -0
  11. wayfinder_paths/adapters/boros_adapter/test_adapter.py +460 -0
  12. wayfinder_paths/adapters/boros_adapter/test_golden.py +156 -0
  13. wayfinder_paths/adapters/boros_adapter/types.py +70 -0
  14. wayfinder_paths/adapters/boros_adapter/utils.py +85 -0
  15. wayfinder_paths/adapters/brap_adapter/README.md +22 -75
  16. wayfinder_paths/adapters/brap_adapter/adapter.py +187 -576
  17. wayfinder_paths/adapters/brap_adapter/examples.json +21 -140
  18. wayfinder_paths/adapters/brap_adapter/manifest.yaml +9 -0
  19. wayfinder_paths/adapters/brap_adapter/test_adapter.py +6 -234
  20. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +180 -92
  21. wayfinder_paths/adapters/hyperlend_adapter/manifest.yaml +9 -0
  22. wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +82 -14
  23. wayfinder_paths/adapters/hyperliquid_adapter/__init__.py +2 -9
  24. wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +586 -61
  25. wayfinder_paths/adapters/hyperliquid_adapter/executor.py +47 -68
  26. wayfinder_paths/adapters/hyperliquid_adapter/manifest.yaml +14 -0
  27. wayfinder_paths/adapters/hyperliquid_adapter/paired_filler.py +2 -3
  28. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter.py +17 -21
  29. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter_live.py +3 -6
  30. wayfinder_paths/adapters/hyperliquid_adapter/test_executor.py +4 -8
  31. wayfinder_paths/adapters/hyperliquid_adapter/test_utils.py +2 -2
  32. wayfinder_paths/adapters/ledger_adapter/README.md +4 -1
  33. wayfinder_paths/adapters/ledger_adapter/adapter.py +3 -3
  34. wayfinder_paths/adapters/ledger_adapter/manifest.yaml +7 -0
  35. wayfinder_paths/adapters/ledger_adapter/test_adapter.py +1 -2
  36. wayfinder_paths/adapters/moonwell_adapter/adapter.py +649 -547
  37. wayfinder_paths/adapters/moonwell_adapter/manifest.yaml +14 -0
  38. wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +160 -239
  39. wayfinder_paths/adapters/multicall_adapter/__init__.py +7 -0
  40. wayfinder_paths/adapters/multicall_adapter/adapter.py +166 -0
  41. wayfinder_paths/adapters/multicall_adapter/manifest.yaml +5 -0
  42. wayfinder_paths/adapters/multicall_adapter/test_adapter.py +97 -0
  43. wayfinder_paths/adapters/pendle_adapter/README.md +102 -0
  44. wayfinder_paths/adapters/pendle_adapter/__init__.py +7 -0
  45. wayfinder_paths/adapters/pendle_adapter/adapter.py +1992 -0
  46. wayfinder_paths/adapters/pendle_adapter/examples.json +11 -0
  47. wayfinder_paths/adapters/pendle_adapter/manifest.yaml +21 -0
  48. wayfinder_paths/adapters/pendle_adapter/test_adapter.py +666 -0
  49. wayfinder_paths/adapters/pool_adapter/manifest.yaml +6 -0
  50. wayfinder_paths/adapters/token_adapter/adapter.py +14 -0
  51. wayfinder_paths/adapters/token_adapter/examples.json +0 -4
  52. wayfinder_paths/adapters/token_adapter/manifest.yaml +7 -0
  53. wayfinder_paths/conftest.py +24 -17
  54. wayfinder_paths/core/__init__.py +0 -3
  55. wayfinder_paths/core/adapters/BaseAdapter.py +0 -25
  56. wayfinder_paths/core/adapters/models.py +17 -7
  57. wayfinder_paths/core/clients/BRAPClient.py +4 -1
  58. wayfinder_paths/core/clients/ClientManager.py +0 -7
  59. wayfinder_paths/core/clients/LedgerClient.py +196 -172
  60. wayfinder_paths/core/clients/TokenClient.py +47 -1
  61. wayfinder_paths/core/clients/WayfinderClient.py +1 -3
  62. wayfinder_paths/core/clients/__init__.py +0 -5
  63. wayfinder_paths/core/clients/protocols.py +21 -35
  64. wayfinder_paths/core/clients/test_ledger_client.py +448 -0
  65. wayfinder_paths/core/config.py +10 -162
  66. wayfinder_paths/core/constants/__init__.py +73 -2
  67. wayfinder_paths/core/constants/base.py +8 -17
  68. wayfinder_paths/core/constants/chains.py +36 -0
  69. wayfinder_paths/core/constants/contracts.py +52 -0
  70. wayfinder_paths/core/constants/erc20_abi.py +0 -1
  71. wayfinder_paths/core/constants/hyperlend_abi.py +0 -4
  72. wayfinder_paths/core/constants/hyperliquid.py +16 -0
  73. wayfinder_paths/core/constants/moonwell_abi.py +0 -15
  74. wayfinder_paths/core/constants/tokens.py +9 -0
  75. wayfinder_paths/core/engine/manifest.py +66 -0
  76. wayfinder_paths/core/strategies/Strategy.py +0 -71
  77. wayfinder_paths/core/strategies/__init__.py +10 -1
  78. wayfinder_paths/core/strategies/opa_loop.py +167 -0
  79. wayfinder_paths/core/utils/evm_helpers.py +5 -15
  80. wayfinder_paths/core/utils/test_transaction.py +289 -0
  81. wayfinder_paths/core/utils/tokens.py +28 -0
  82. wayfinder_paths/core/utils/transaction.py +57 -8
  83. wayfinder_paths/core/utils/web3.py +8 -3
  84. wayfinder_paths/mcp/__init__.py +5 -0
  85. wayfinder_paths/mcp/preview.py +185 -0
  86. wayfinder_paths/mcp/scripting.py +84 -0
  87. wayfinder_paths/mcp/server.py +52 -0
  88. wayfinder_paths/mcp/state/profile_store.py +195 -0
  89. wayfinder_paths/mcp/state/store.py +89 -0
  90. wayfinder_paths/mcp/test_scripting.py +267 -0
  91. wayfinder_paths/mcp/tools/__init__.py +0 -0
  92. wayfinder_paths/mcp/tools/balances.py +290 -0
  93. wayfinder_paths/mcp/tools/discovery.py +158 -0
  94. wayfinder_paths/mcp/tools/execute.py +770 -0
  95. wayfinder_paths/mcp/tools/hyperliquid.py +931 -0
  96. wayfinder_paths/mcp/tools/quotes.py +288 -0
  97. wayfinder_paths/mcp/tools/run_script.py +286 -0
  98. wayfinder_paths/mcp/tools/strategies.py +188 -0
  99. wayfinder_paths/mcp/tools/tokens.py +46 -0
  100. wayfinder_paths/mcp/tools/wallets.py +354 -0
  101. wayfinder_paths/mcp/utils.py +129 -0
  102. wayfinder_paths/policies/enso.py +1 -2
  103. wayfinder_paths/policies/hyper_evm.py +6 -3
  104. wayfinder_paths/policies/hyperlend.py +1 -2
  105. wayfinder_paths/policies/hyperliquid.py +1 -1
  106. wayfinder_paths/policies/lifi.py +18 -0
  107. wayfinder_paths/policies/moonwell.py +12 -7
  108. wayfinder_paths/policies/prjx.py +1 -3
  109. wayfinder_paths/policies/util.py +8 -2
  110. wayfinder_paths/run_strategy.py +97 -300
  111. wayfinder_paths/strategies/basis_trading_strategy/constants.py +3 -1
  112. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +47 -133
  113. wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +24 -53
  114. wayfinder_paths/strategies/boros_hype_strategy/__init__.py +3 -0
  115. wayfinder_paths/strategies/boros_hype_strategy/boros_ops_mixin.py +450 -0
  116. wayfinder_paths/strategies/boros_hype_strategy/constants.py +255 -0
  117. wayfinder_paths/strategies/boros_hype_strategy/examples.json +37 -0
  118. wayfinder_paths/strategies/boros_hype_strategy/hyperevm_ops_mixin.py +114 -0
  119. wayfinder_paths/strategies/boros_hype_strategy/hyperliquid_ops_mixin.py +642 -0
  120. wayfinder_paths/strategies/boros_hype_strategy/manifest.yaml +36 -0
  121. wayfinder_paths/strategies/boros_hype_strategy/planner.py +460 -0
  122. wayfinder_paths/strategies/boros_hype_strategy/risk_ops_mixin.py +886 -0
  123. wayfinder_paths/strategies/boros_hype_strategy/snapshot_mixin.py +494 -0
  124. wayfinder_paths/strategies/boros_hype_strategy/strategy.py +1194 -0
  125. wayfinder_paths/strategies/boros_hype_strategy/test_planner_golden.py +374 -0
  126. wayfinder_paths/{templates/strategy → strategies/boros_hype_strategy}/test_strategy.py +99 -63
  127. wayfinder_paths/strategies/boros_hype_strategy/types.py +365 -0
  128. wayfinder_paths/strategies/boros_hype_strategy/withdraw_mixin.py +997 -0
  129. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +15 -23
  130. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +27 -62
  131. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +84 -58
  132. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/test_strategy.py +5 -15
  133. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +69 -164
  134. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +43 -76
  135. wayfinder_paths/tests/test_mcp_quote_swap.py +165 -0
  136. wayfinder_paths/tests/test_test_coverage.py +1 -4
  137. wayfinder_paths-0.1.24.dist-info/METADATA +378 -0
  138. wayfinder_paths-0.1.24.dist-info/RECORD +185 -0
  139. {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.24.dist-info}/WHEEL +1 -1
  140. wayfinder_paths/core/clients/WalletClient.py +0 -41
  141. wayfinder_paths/core/engine/StrategyJob.py +0 -110
  142. wayfinder_paths/core/services/test_local_evm_txn.py +0 -145
  143. wayfinder_paths/scripts/create_strategy.py +0 -139
  144. wayfinder_paths/scripts/make_wallets.py +0 -142
  145. wayfinder_paths/templates/adapter/README.md +0 -150
  146. wayfinder_paths/templates/adapter/adapter.py +0 -16
  147. wayfinder_paths/templates/adapter/examples.json +0 -8
  148. wayfinder_paths/templates/adapter/test_adapter.py +0 -30
  149. wayfinder_paths/templates/strategy/README.md +0 -186
  150. wayfinder_paths/templates/strategy/examples.json +0 -11
  151. wayfinder_paths/templates/strategy/strategy.py +0 -35
  152. wayfinder_paths/tests/test_smoke_manifest.py +0 -63
  153. wayfinder_paths-0.1.22.dist-info/METADATA +0 -355
  154. wayfinder_paths-0.1.22.dist-info/RECORD +0 -129
  155. /wayfinder_paths/{scripts → mcp/state}/__init__.py +0 -0
  156. {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.24.dist-info}/LICENSE +0 -0
@@ -12,7 +12,6 @@ from wayfinder_paths.adapters.brap_adapter.adapter import BRAPAdapter
12
12
  from wayfinder_paths.adapters.ledger_adapter.adapter import LedgerAdapter
13
13
  from wayfinder_paths.adapters.pool_adapter.adapter import PoolAdapter
14
14
  from wayfinder_paths.adapters.token_adapter.adapter import TokenAdapter
15
- from wayfinder_paths.core.constants.base import DEFAULT_SLIPPAGE
16
15
  from wayfinder_paths.core.strategies.descriptors import (
17
16
  Complexity,
18
17
  Directionality,
@@ -207,15 +206,6 @@ class StablecoinYieldStrategy(Strategy):
207
206
  strategy_wallet_signing_callback=self.strategy_wallet_signing_callback,
208
207
  )
209
208
 
210
- self.register_adapters(
211
- [
212
- balance,
213
- token_adapter,
214
- ledger_adapter,
215
- pool_adapter,
216
- brap_adapter,
217
- ]
218
- )
219
209
  self.balance_adapter = balance
220
210
  self.token_adapter = token_adapter
221
211
  self.ledger_adapter = ledger_adapter
@@ -260,7 +250,7 @@ class StablecoinYieldStrategy(Strategy):
260
250
  for token_id in self.tracked_token_ids:
261
251
  try:
262
252
  success, balance_wei = await self.balance_adapter.get_balance(
263
- query=token_id,
253
+ token_id=token_id,
264
254
  wallet_address=strategy_address,
265
255
  )
266
256
  if success and balance_wei:
@@ -373,11 +363,9 @@ class StablecoinYieldStrategy(Strategy):
373
363
  logger.info(f"Found {len(txns)} non-deposit transactions")
374
364
 
375
365
  for txn in txns:
376
- op_data = txn.get("data", {}).get("op_data", {})
377
- # Track any token that was swapped TO
366
+ op_data = txn.get("op_data", {})
378
367
  if op_data.get("to_token_id"):
379
368
  self._track_token(op_data.get("to_token_id"))
380
- # Track any token that was swapped FROM
381
369
  if op_data.get("from_token_id"):
382
370
  self._track_token(op_data.get("from_token_id"))
383
371
 
@@ -392,29 +380,30 @@ class StablecoinYieldStrategy(Strategy):
392
380
  txns = []
393
381
 
394
382
  if txns and txns[-1].get("operation") != "WITHDRAW":
395
- pos = txns[-1].get("data").get("op_data")
396
- success, token_info = await self.token_adapter.get_token(
397
- pos.get("to_token_id")
398
- )
399
- if not success:
400
- token_info = {}
401
- self.current_pool = {
402
- "token_id": token_info.get("token_id"),
403
- "name": token_info.get("name"),
404
- "symbol": token_info.get("symbol"),
405
- "decimals": token_info.get("decimals"),
406
- "address": token_info.get("address"),
407
- "chain": token_info.get("chain"),
408
- }
409
- # Track the current pool token
410
- if token_info.get("token_id"):
411
- self._track_token(token_info.get("token_id"))
383
+ last_txn = txns[-1]
384
+ pos = last_txn.get("op_data", {})
385
+ if pos and pos.get("to_token_id"):
386
+ success, token_info = await self.token_adapter.get_token(
387
+ pos.get("to_token_id")
388
+ )
389
+ if not success:
390
+ token_info = {}
391
+ self.current_pool = {
392
+ "token_id": token_info.get("token_id"),
393
+ "name": token_info.get("name"),
394
+ "symbol": token_info.get("symbol"),
395
+ "decimals": token_info.get("decimals"),
396
+ "address": token_info.get("address"),
397
+ "chain": token_info.get("chain"),
398
+ }
399
+ if token_info.get("token_id"):
400
+ self._track_token(token_info.get("token_id"))
412
401
 
413
- success, reports = await self.pool_adapter.get_pools_by_ids(
414
- pool_ids=[self.current_pool.get("token_id")]
415
- )
416
- if success and reports.get("pools"):
417
- self.current_pool_data = reports.get("pools", [])[0]
402
+ success, reports = await self.pool_adapter.get_pools_by_ids(
403
+ pool_ids=[self.current_pool.get("token_id")]
404
+ )
405
+ if success and reports.get("pools"):
406
+ self.current_pool_data = reports.get("pools", [])[0]
418
407
 
419
408
  pool_ids = []
420
409
  pool_id = self.current_pool.get("token_id", None)
@@ -489,7 +478,7 @@ class StablecoinYieldStrategy(Strategy):
489
478
  success,
490
479
  current_pool_balance_raw,
491
480
  ) = await self.balance_adapter.get_balance(
492
- query=pool_address,
481
+ token_address=pool_address,
493
482
  wallet_address=user_address,
494
483
  chain_id=chain_id,
495
484
  )
@@ -506,7 +495,6 @@ class StablecoinYieldStrategy(Strategy):
506
495
  == self.current_pool.get("chain").get("id")
507
496
  else None
508
497
  )
509
- # Refresh all tracked balances from blockchain
510
498
  await self._refresh_tracked_balances()
511
499
  logger.info(
512
500
  f"Refreshed balances for {len(self.tracked_balances)} tracked tokens"
@@ -537,7 +525,7 @@ class StablecoinYieldStrategy(Strategy):
537
525
 
538
526
  if self.usdc_token_info:
539
527
  status, raw_balance = await self.balance_adapter.get_balance(
540
- query=self.usdc_token_info.get("token_id"),
528
+ token_id=self.usdc_token_info.get("token_id"),
541
529
  wallet_address=self._get_strategy_wallet_address(),
542
530
  )
543
531
  if not status or not raw_balance:
@@ -575,7 +563,6 @@ class StablecoinYieldStrategy(Strategy):
575
563
 
576
564
  async def _infer_active_pool_from_tracked_tokens(self):
577
565
  try:
578
- # Refresh balances for tracked tokens
579
566
  await self._refresh_tracked_balances()
580
567
 
581
568
  usdc_token_id = self.usdc_token_info.get("token_id")
@@ -584,7 +571,6 @@ class StablecoinYieldStrategy(Strategy):
584
571
  best_token_id = None
585
572
  best_balance_wei = 0
586
573
 
587
- # Find the non-gas, non-USDC token with the largest balance
588
574
  for token_id, balance_wei in self.tracked_balances.items():
589
575
  if balance_wei <= 0:
590
576
  continue
@@ -593,7 +579,6 @@ class StablecoinYieldStrategy(Strategy):
593
579
  if token_id == usdc_token_id:
594
580
  continue
595
581
 
596
- # Prefer tokens with larger balances
597
582
  if balance_wei > best_balance_wei:
598
583
  best_token_id = token_id
599
584
  best_balance_wei = balance_wei
@@ -608,7 +593,7 @@ class StablecoinYieldStrategy(Strategy):
608
593
  strategy_address = self._get_strategy_wallet_address()
609
594
  try:
610
595
  success, onchain_balance = await self.balance_adapter.get_balance(
611
- query=token.get("token_id"),
596
+ token_id=token.get("token_id"),
612
597
  wallet_address=strategy_address,
613
598
  )
614
599
  if success and onchain_balance:
@@ -686,7 +671,7 @@ class StablecoinYieldStrategy(Strategy):
686
671
  main_usdc_status,
687
672
  main_usdc_balance,
688
673
  ) = await self.balance_adapter.get_balance(
689
- query=token_info.get("token_id"),
674
+ token_id=token_info.get("token_id"),
690
675
  wallet_address=self._get_main_wallet_address(),
691
676
  )
692
677
  if main_usdc_status and main_usdc_balance is not None:
@@ -730,7 +715,7 @@ class StablecoinYieldStrategy(Strategy):
730
715
  _,
731
716
  main_gas_raw,
732
717
  ) = await self.balance_adapter.get_balance(
733
- query=gas_token_id,
718
+ token_id=gas_token_id,
734
719
  wallet_address=self._get_main_wallet_address(),
735
720
  )
736
721
  main_gas_int = (
@@ -754,14 +739,14 @@ class StablecoinYieldStrategy(Strategy):
754
739
  _,
755
740
  main_gas_raw,
756
741
  ) = await self.balance_adapter.get_balance(
757
- query=gas_token_id,
742
+ token_id=gas_token_id,
758
743
  wallet_address=self._get_main_wallet_address(),
759
744
  )
760
745
  (
761
746
  _,
762
747
  strategy_gas_raw,
763
748
  ) = await self.balance_adapter.get_balance(
764
- query=gas_token_id,
749
+ token_id=gas_token_id,
765
750
  wallet_address=self._get_strategy_wallet_address(),
766
751
  )
767
752
  main_gas_int = (
@@ -794,7 +779,6 @@ class StablecoinYieldStrategy(Strategy):
794
779
  f"Need at least {required_gas} {gas_symbol} on Base for gas. You have: {total_gas}",
795
780
  )
796
781
 
797
- # Transfer main token if provided
798
782
  if main_token_amount > 0:
799
783
  self.current_pool_balance = int(
800
784
  main_token_amount * (10 ** self.current_pool.get("decimals"))
@@ -802,7 +786,6 @@ class StablecoinYieldStrategy(Strategy):
802
786
  self.DEPOSIT_USDC = main_token_amount
803
787
  logger.info(f"Set deposit amount to {main_token_amount} USDC")
804
788
 
805
- # Transfer USDC from main to strategy wallet
806
789
  logger.info("Initiating USDC transfer from main to strategy wallet")
807
790
  (
808
791
  success,
@@ -885,7 +868,7 @@ class StablecoinYieldStrategy(Strategy):
885
868
  _,
886
869
  self.current_pool_balance,
887
870
  ) = await self.balance_adapter.get_balance(
888
- query=self.current_pool.get("address"),
871
+ token_address=self.current_pool.get("address"),
889
872
  wallet_address=self._get_strategy_wallet_address(),
890
873
  chain_id=self.current_pool.get("chain").get("id"),
891
874
  )
@@ -901,76 +884,26 @@ class StablecoinYieldStrategy(Strategy):
901
884
  logger.info(
902
885
  f"Need to swap from {self.current_pool.get('symbol')} to USDC before withdrawal"
903
886
  )
904
- quotes = {}
905
- for attempt in range(4):
906
- logger.info(
907
- f"Getting swap quote (attempt {attempt + 1}/4) with slippage: {DEFAULT_SLIPPAGE * (attempt + 1)}"
908
- )
909
- try:
910
- success, quotes = await self.brap_adapter.get_swap_quote(
911
- from_token_address=self.current_pool.get("address"),
912
- to_token_address=self.usdc_token_info.get("address"),
913
- from_chain_id=self.current_pool.get("chain").get("id"),
914
- to_chain_id=self.usdc_token_info.get("chain").get("id"),
915
- from_address=self._get_strategy_wallet_address(),
916
- to_address=self._get_strategy_wallet_address(),
917
- amount=str(self.current_pool_balance),
918
- slippage=DEFAULT_SLIPPAGE * (attempt + 1),
919
- )
920
- if (
921
- success
922
- and isinstance(quotes, dict)
923
- and quotes.get("best_quote")
924
- ):
925
- logger.info("Successfully obtained swap quote")
926
- break
927
- except Exception as e:
928
- logger.warning(f"Quote attempt {attempt + 1} failed: {e}")
929
- if attempt == 3:
930
- logger.error("All quote attempts failed")
931
-
932
- best_quote = quotes.get("best_quote") if isinstance(quotes, dict) else None
933
- if not best_quote:
887
+ success, quote = await self.brap_adapter.best_quote(
888
+ from_token_address=self.current_pool.get("address"),
889
+ to_token_address=self.usdc_token_info.get("address"),
890
+ from_chain_id=self.current_pool.get("chain").get("id"),
891
+ to_chain_id=self.usdc_token_info.get("chain").get("id"),
892
+ from_address=self._get_strategy_wallet_address(),
893
+ amount=str(self.current_pool_balance),
894
+ retries=4,
895
+ )
896
+ if not success:
934
897
  return (
935
898
  False,
936
899
  "Could not swap tokens out due to market conditions (balances too small to move or slippage required is too high) please manually move funds out",
937
900
  )
938
901
 
939
- if not best_quote.get("output_amount") or not best_quote.get(
940
- "input_amount"
941
- ):
942
- return (False, "Swap quote missing required fields")
943
-
944
- if not best_quote.get("from_amount_usd"):
945
- input_amount = int(best_quote.get("input_amount"))
946
- if self.current_pool.get("token_id") == self.usdc_token_info.get(
947
- "token_id"
948
- ):
949
- best_quote["from_amount_usd"] = float(input_amount) / (
950
- 10 ** self.current_pool.get("decimals")
951
- )
952
- else:
953
- best_quote["from_amount_usd"] = await self._get_pool_usd_value(
954
- self.current_pool, input_amount
955
- )
956
-
957
- if not best_quote.get("to_amount_usd"):
958
- output_amount = int(best_quote.get("output_amount"))
959
- best_quote["to_amount_usd"] = float(
960
- output_amount
961
- ) / 10 ** self.usdc_token_info.get("decimals")
962
-
963
- if not self.brap_adapter:
964
- return (
965
- False,
966
- "BRAP adapter not initialized; cannot unwind position.",
967
- )
968
-
969
902
  success, swap_result = await self.brap_adapter.swap_from_quote(
970
903
  self.current_pool,
971
904
  self.usdc_token_info,
972
905
  self._get_strategy_wallet_address(),
973
- best_quote,
906
+ quote,
974
907
  strategy_name=self.name,
975
908
  )
976
909
  if not success:
@@ -982,7 +915,7 @@ class StablecoinYieldStrategy(Strategy):
982
915
  await self._sweep_wallet(self.usdc_token_info)
983
916
 
984
917
  status, raw_balance = await self.balance_adapter.get_balance(
985
- query=self.usdc_token_info.get("token_id"),
918
+ token_id=self.usdc_token_info.get("token_id"),
986
919
  wallet_address=self._get_strategy_wallet_address(),
987
920
  )
988
921
  usdc_amount = 0.0
@@ -994,7 +927,7 @@ class StablecoinYieldStrategy(Strategy):
994
927
  gas_amount = 0.0
995
928
  if self.gas_token:
996
929
  status, raw_gas = await self.balance_adapter.get_balance(
997
- query=self.gas_token.get("token_id"),
930
+ token_id=self.gas_token.get("token_id"),
998
931
  wallet_address=self._get_strategy_wallet_address(),
999
932
  )
1000
933
  if status and raw_gas:
@@ -1030,7 +963,6 @@ class StablecoinYieldStrategy(Strategy):
1030
963
 
1031
964
  transferred_items = []
1032
965
 
1033
- # Transfer USDC to main wallet
1034
966
  usdc_ok, usdc_raw = await self.balance_adapter.get_balance(
1035
967
  token_id="usd-coin-base",
1036
968
  wallet_address=strategy_address,
@@ -1043,7 +975,7 @@ class StablecoinYieldStrategy(Strategy):
1043
975
  success,
1044
976
  msg,
1045
977
  ) = await self.balance_adapter.move_from_strategy_wallet_to_main_wallet(
1046
- query="usd-coin-base",
978
+ token_id="usd-coin-base",
1047
979
  amount=usdc_balance,
1048
980
  strategy_name=self.name,
1049
981
  skip_ledger=False,
@@ -1053,7 +985,6 @@ class StablecoinYieldStrategy(Strategy):
1053
985
  else:
1054
986
  logger.warning(f"USDC transfer failed: {msg}")
1055
987
 
1056
- # Transfer ETH (minus reserve for tx fees) to main wallet
1057
988
  eth_ok, eth_raw = await self.balance_adapter.get_balance(
1058
989
  token_id="ethereum-base",
1059
990
  wallet_address=strategy_address,
@@ -1068,7 +999,7 @@ class StablecoinYieldStrategy(Strategy):
1068
999
  success,
1069
1000
  msg,
1070
1001
  ) = await self.balance_adapter.move_from_strategy_wallet_to_main_wallet(
1071
- query="ethereum-base",
1002
+ token_id="ethereum-base",
1072
1003
  amount=transferable_eth,
1073
1004
  strategy_name=self.name,
1074
1005
  skip_ledger=False,
@@ -1091,12 +1022,16 @@ class StablecoinYieldStrategy(Strategy):
1091
1022
  return None
1092
1023
  for transaction in data.get("transactions", []):
1093
1024
  op_data = transaction.get("op_data", {})
1094
- if op_data.get("type") == "SWAP" and op_data.get(
1095
- "to_token_id"
1096
- ).lower() not in [
1097
- "usd-coin-base",
1098
- "base_0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1099
- ]:
1025
+ to_token = op_data.get("to_token_id")
1026
+ if (
1027
+ op_data.get("type") == "SWAP"
1028
+ and to_token
1029
+ and str(to_token).lower()
1030
+ not in [
1031
+ "usd-coin-base",
1032
+ "base_0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1033
+ ]
1034
+ ):
1100
1035
  created_str = transaction.get("created")
1101
1036
  if not created_str:
1102
1037
  continue
@@ -1262,7 +1197,7 @@ class StablecoinYieldStrategy(Strategy):
1262
1197
  _,
1263
1198
  refreshed_pool_balance,
1264
1199
  ) = await self.balance_adapter.get_balance(
1265
- query=pool.get("address"),
1200
+ token_address=pool.get("address"),
1266
1201
  wallet_address=strategy_address,
1267
1202
  chain_id=pool.get("chain").get("id"),
1268
1203
  )
@@ -1271,7 +1206,6 @@ class StablecoinYieldStrategy(Strategy):
1271
1206
  pass
1272
1207
 
1273
1208
  async def _sweep_wallet(self, target_token):
1274
- # Refresh tracked balances
1275
1209
  await self._refresh_tracked_balances()
1276
1210
 
1277
1211
  target_token_id = target_token.get("token_id")
@@ -1279,23 +1213,19 @@ class StablecoinYieldStrategy(Strategy):
1279
1213
  target_address = target_token.get("address", "").lower()
1280
1214
  gas_token_id = self.gas_token.get("token_id") if self.gas_token else None
1281
1215
 
1282
- # Swap all non-target, non-gas tokens to the target
1283
1216
  for token_id, balance_wei in list(self.tracked_balances.items()):
1284
- # Skip if no balance
1285
1217
  if balance_wei <= 0:
1286
1218
  continue
1287
1219
 
1288
- # Skip gas token
1289
1220
  if token_id == gas_token_id:
1290
1221
  continue
1291
1222
 
1292
- # Skip if it's already the target token
1293
1223
  if token_id == target_token_id:
1294
1224
  continue
1295
1225
 
1296
1226
  try:
1297
1227
  success, fresh_balance = await self.balance_adapter.get_balance(
1298
- query=token_id,
1228
+ token_id=token_id,
1299
1229
  wallet_address=self._get_strategy_wallet_address(),
1300
1230
  )
1301
1231
  if not success or not fresh_balance or int(fresh_balance) <= 0:
@@ -1329,12 +1259,10 @@ class StablecoinYieldStrategy(Strategy):
1329
1259
  logger.error(f"Error sweeping {token_id}: {e}")
1330
1260
  continue
1331
1261
 
1332
- # Track the target token
1333
1262
  self._track_token(target_token_id)
1334
- # Refresh target token balance
1335
1263
  try:
1336
1264
  success, target_balance = await self.balance_adapter.get_balance(
1337
- query=target_token_id,
1265
+ token_id=target_token_id,
1338
1266
  wallet_address=self._get_strategy_wallet_address(),
1339
1267
  )
1340
1268
  if success and target_balance:
@@ -1351,7 +1279,7 @@ class StablecoinYieldStrategy(Strategy):
1351
1279
 
1352
1280
  required_gas = int(self.MIN_GAS * (10 ** self.gas_token.get("decimals")))
1353
1281
  _, current_gas = await self.balance_adapter.get_balance(
1354
- query=self.gas_token.get("token_id"),
1282
+ token_id=self.gas_token.get("token_id"),
1355
1283
  wallet_address=strategy_address,
1356
1284
  )
1357
1285
  if current_gas >= required_gas:
@@ -1399,22 +1327,15 @@ class StablecoinYieldStrategy(Strategy):
1399
1327
  if chain_id != self.usdc_token_info.get("chain").get("id"):
1400
1328
  return 0.0
1401
1329
 
1402
- success, exit_quotes = await self.brap_adapter.get_swap_quote(
1330
+ success, best_quote = await self.brap_adapter.best_quote(
1403
1331
  from_token_address=token.get("address"),
1404
1332
  to_token_address=self.usdc_token_info.get("address"),
1405
1333
  from_chain_id=chain_id,
1406
1334
  to_chain_id=self.usdc_token_info.get("chain").get("id"),
1407
1335
  from_address=self._get_strategy_wallet_address(),
1408
- to_address=self._get_strategy_wallet_address(),
1409
1336
  amount=str(amount),
1410
1337
  )
1411
- if not success:
1412
- return 0.0
1413
-
1414
- best_quote = (
1415
- exit_quotes.get("best_quote") if isinstance(exit_quotes, dict) else None
1416
- )
1417
- if not best_quote:
1338
+ if not success or not isinstance(best_quote, dict):
1418
1339
  return None
1419
1340
  current_pool_usd_value = best_quote.get("output_amount")
1420
1341
 
@@ -1423,18 +1344,15 @@ class StablecoinYieldStrategy(Strategy):
1423
1344
  )
1424
1345
 
1425
1346
  async def _get_non_gas_balances(self) -> list[dict[str, Any]]:
1426
- # Refresh tracked balances
1427
1347
  await self._refresh_tracked_balances()
1428
1348
 
1429
1349
  gas_token_id = self.gas_token.get("token_id") if self.gas_token else None
1430
1350
  results = []
1431
1351
 
1432
1352
  for token_id, balance_wei in self.tracked_balances.items():
1433
- # Skip gas token
1434
1353
  if token_id == gas_token_id:
1435
1354
  continue
1436
1355
 
1437
- # Skip zero balances
1438
1356
  if balance_wei <= 0:
1439
1357
  continue
1440
1358
 
@@ -1538,21 +1456,15 @@ class StablecoinYieldStrategy(Strategy):
1538
1456
  try:
1539
1457
  apy_pct = pool_data.get("combined_apy_pct") or pool_data.get("apy") or 0
1540
1458
  combined_apy_pct = float(apy_pct) / 100
1541
- success, quotes = await self.brap_adapter.get_swap_quote(
1459
+ success, best_quote = await self.brap_adapter.best_quote(
1542
1460
  from_token_address=current_token.get("address"),
1543
1461
  to_token_address=token.get("address"),
1544
1462
  from_chain_id=current_token.get("chain").get("id"),
1545
1463
  to_chain_id=token.get("chain").get("id"),
1546
1464
  from_address=self._get_strategy_wallet_address(),
1547
- to_address=self._get_strategy_wallet_address(),
1548
1465
  amount=str(current_token_balance),
1549
1466
  )
1550
- if not success:
1551
- return None
1552
- if not isinstance(quotes, dict):
1553
- return None
1554
- best_quote = quotes.get("best_quote")
1555
- if not best_quote:
1467
+ if not success or not isinstance(best_quote, dict):
1556
1468
  return None
1557
1469
 
1558
1470
  target_pool_usd_val = await self._get_pool_usd_value(
@@ -1602,7 +1514,7 @@ class StablecoinYieldStrategy(Strategy):
1602
1514
 
1603
1515
  async def _status(self) -> StatusDict:
1604
1516
  gas_success, gas_balance_wei = await self.balance_adapter.get_balance(
1605
- query=self.gas_token.get("token_id"),
1517
+ token_id=self.gas_token.get("token_id"),
1606
1518
  wallet_address=self._get_strategy_wallet_address(),
1607
1519
  )
1608
1520
  gas_balance = (
@@ -1612,7 +1524,6 @@ class StablecoinYieldStrategy(Strategy):
1612
1524
  )
1613
1525
 
1614
1526
  if not self.DEPOSIT_USDC:
1615
- # No deposits recorded - report minimal status
1616
1527
  status_payload = {
1617
1528
  "info": "No recorded strategy deposits.",
1618
1529
  "idle_usd": 0.0,
@@ -1692,7 +1603,6 @@ class StablecoinYieldStrategy(Strategy):
1692
1603
  return [f"({wallet_id}) && (({approve_enso}) || ({swap_enso})) "]
1693
1604
 
1694
1605
  async def partial_liquidate(self, usd_value: float) -> StatusTuple:
1695
- # Refresh tracked balances
1696
1606
  await self._refresh_tracked_balances()
1697
1607
 
1698
1608
  usdc_token_id = self.usdc_token_info.get("token_id")
@@ -1702,12 +1612,10 @@ class StablecoinYieldStrategy(Strategy):
1702
1612
  available_usdc_wei = self.tracked_balances.get(usdc_token_id, 0)
1703
1613
  available_usdc_usd = float(available_usdc_wei) / (10**usdc_decimals)
1704
1614
 
1705
- # Liquidate non-USDC, non-gas, non-current-pool tokens first
1706
1615
  for token_id, balance_wei in list(self.tracked_balances.items()):
1707
1616
  if available_usdc_usd >= usd_value:
1708
1617
  break
1709
1618
 
1710
- # Skip USDC, gas, and current pool
1711
1619
  if token_id == usdc_token_id:
1712
1620
  continue
1713
1621
  if token_id == gas_token_id:
@@ -1715,7 +1623,6 @@ class StablecoinYieldStrategy(Strategy):
1715
1623
  if self.current_pool and token_id == self.current_pool.get("token_id"):
1716
1624
  continue
1717
1625
 
1718
- # Skip zero balances
1719
1626
  if balance_wei <= 0:
1720
1627
  continue
1721
1628
 
@@ -1759,7 +1666,7 @@ class StablecoinYieldStrategy(Strategy):
1759
1666
 
1760
1667
  # Refresh USDC balance after swaps
1761
1668
  success, usdc_wei = await self.balance_adapter.get_balance(
1762
- query=usdc_token_id,
1669
+ token_id=usdc_token_id,
1763
1670
  wallet_address=self._get_strategy_wallet_address(),
1764
1671
  )
1765
1672
  if success and usdc_wei:
@@ -1767,7 +1674,6 @@ class StablecoinYieldStrategy(Strategy):
1767
1674
  available_usdc_usd = float(available_usdc_wei) / (10**usdc_decimals)
1768
1675
  self._update_balance(usdc_token_id, available_usdc_wei)
1769
1676
 
1770
- # If still not enough, liquidate from current pool
1771
1677
  if (
1772
1678
  available_usdc_usd < usd_value
1773
1679
  and self.current_pool
@@ -1802,9 +1708,8 @@ class StablecoinYieldStrategy(Strategy):
1802
1708
  except Exception as e:
1803
1709
  logger.error(f"Error swapping pool to USDC: {e}")
1804
1710
 
1805
- # Refresh USDC balance again
1806
1711
  success, usdc_wei = await self.balance_adapter.get_balance(
1807
- query=usdc_token_id,
1712
+ token_id=usdc_token_id,
1808
1713
  wallet_address=self._get_strategy_wallet_address(),
1809
1714
  )
1810
1715
  if success and usdc_wei: