wayfinder-paths 0.1.11__py3-none-any.whl → 0.1.14__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 (66) hide show
  1. wayfinder_paths/adapters/balance_adapter/README.md +13 -14
  2. wayfinder_paths/adapters/balance_adapter/adapter.py +36 -39
  3. wayfinder_paths/adapters/balance_adapter/test_adapter.py +123 -0
  4. wayfinder_paths/adapters/brap_adapter/README.md +11 -16
  5. wayfinder_paths/adapters/brap_adapter/adapter.py +87 -75
  6. wayfinder_paths/adapters/brap_adapter/examples.json +63 -52
  7. wayfinder_paths/adapters/brap_adapter/test_adapter.py +121 -59
  8. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +22 -23
  9. wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +114 -60
  10. wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +1 -1
  11. wayfinder_paths/adapters/hyperliquid_adapter/executor.py +44 -5
  12. wayfinder_paths/adapters/hyperliquid_adapter/test_executor.py +104 -0
  13. wayfinder_paths/adapters/moonwell_adapter/adapter.py +0 -3
  14. wayfinder_paths/adapters/pool_adapter/README.md +11 -27
  15. wayfinder_paths/adapters/pool_adapter/adapter.py +11 -37
  16. wayfinder_paths/adapters/pool_adapter/examples.json +6 -7
  17. wayfinder_paths/adapters/pool_adapter/test_adapter.py +8 -8
  18. wayfinder_paths/adapters/token_adapter/README.md +2 -14
  19. wayfinder_paths/adapters/token_adapter/adapter.py +16 -10
  20. wayfinder_paths/adapters/token_adapter/examples.json +4 -8
  21. wayfinder_paths/adapters/token_adapter/test_adapter.py +5 -3
  22. wayfinder_paths/core/clients/BRAPClient.py +103 -62
  23. wayfinder_paths/core/clients/ClientManager.py +1 -68
  24. wayfinder_paths/core/clients/HyperlendClient.py +127 -66
  25. wayfinder_paths/core/clients/LedgerClient.py +1 -4
  26. wayfinder_paths/core/clients/PoolClient.py +126 -88
  27. wayfinder_paths/core/clients/TokenClient.py +92 -37
  28. wayfinder_paths/core/clients/WalletClient.py +28 -58
  29. wayfinder_paths/core/clients/WayfinderClient.py +33 -166
  30. wayfinder_paths/core/clients/__init__.py +0 -2
  31. wayfinder_paths/core/clients/protocols.py +35 -52
  32. wayfinder_paths/core/clients/sdk_example.py +37 -22
  33. wayfinder_paths/core/config.py +60 -224
  34. wayfinder_paths/core/engine/StrategyJob.py +7 -55
  35. wayfinder_paths/core/services/local_evm_txn.py +28 -10
  36. wayfinder_paths/core/services/local_token_txn.py +1 -1
  37. wayfinder_paths/core/strategies/Strategy.py +3 -5
  38. wayfinder_paths/core/strategies/descriptors.py +7 -0
  39. wayfinder_paths/core/utils/evm_helpers.py +7 -3
  40. wayfinder_paths/core/utils/wallets.py +12 -19
  41. wayfinder_paths/core/wallets/README.md +1 -1
  42. wayfinder_paths/run_strategy.py +8 -17
  43. wayfinder_paths/scripts/create_strategy.py +5 -5
  44. wayfinder_paths/scripts/make_wallets.py +5 -5
  45. wayfinder_paths/scripts/run_strategy.py +3 -3
  46. wayfinder_paths/strategies/basis_trading_strategy/snapshot_mixin.py +1 -1
  47. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +206 -526
  48. wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +228 -11
  49. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +2 -2
  50. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +41 -25
  51. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +54 -9
  52. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/README.md +1 -1
  53. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +10 -9
  54. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/test_strategy.py +12 -6
  55. wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +3 -3
  56. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +110 -78
  57. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +44 -21
  58. wayfinder_paths/templates/adapter/README.md +1 -1
  59. wayfinder_paths/templates/strategy/README.md +3 -3
  60. wayfinder_paths/templates/strategy/test_strategy.py +3 -2
  61. {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.14.dist-info}/METADATA +21 -59
  62. {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.14.dist-info}/RECORD +64 -65
  63. wayfinder_paths/core/clients/AuthClient.py +0 -83
  64. wayfinder_paths/core/settings.py +0 -61
  65. {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.14.dist-info}/LICENSE +0 -0
  66. {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.14.dist-info}/WHEEL +0 -0
@@ -523,7 +523,8 @@ async def test_atomic_deposit_iteration_swaps_from_eth_when_borrow_surfaces_as_e
523
523
  WSTETH_TOKEN_ID: 0,
524
524
  }
525
525
 
526
- async def get_balance_side_effect(*, token_id: str, wallet_address: str, **_):
526
+ async def get_balance_side_effect(*, query: str, wallet_address: str, **_):
527
+ token_id = query if isinstance(query, str) else (query or {}).get("token_id")
527
528
  return (True, balances.get(token_id, 0))
528
529
 
529
530
  strategy.balance_adapter.get_balance = AsyncMock(
@@ -587,7 +588,8 @@ async def test_complete_unpaired_weth_borrow_uses_eth_inventory(
587
588
  WSTETH_TOKEN_ID: 0,
588
589
  }
589
590
 
590
- async def get_balance_side_effect(*, token_id: str, wallet_address: str):
591
+ async def get_balance_side_effect(*, query: str, wallet_address: str):
592
+ token_id = query if isinstance(query, str) else (query or {}).get("token_id")
591
593
  return (True, balances.get(token_id, 0))
592
594
 
593
595
  strategy.balance_adapter.get_balance = AsyncMock(
@@ -631,8 +633,10 @@ async def test_sweep_token_balances_sweeps_tokens(strategy, mock_adapter_respons
631
633
  strategy.min_withdraw_usd = 1.0
632
634
 
633
635
  # Mock balance returns (has some WETH dust)
634
- def balance_side_effect(token_id, wallet_address):
635
- if "weth" in token_id.lower():
636
+ def balance_side_effect(*, query, wallet_address, **_):
637
+ token_id = query if isinstance(query, str) else (query or {}).get("token_id")
638
+ token_id_str = (token_id or "").lower()
639
+ if "weth" in token_id_str:
636
640
  return (True, 100 * 10**18) # 100 WETH
637
641
  return (True, 0)
638
642
 
@@ -751,7 +755,8 @@ async def test_partial_liquidate_prefers_wsteth_when_excess(strategy):
751
755
  # Wallet balances (raw)
752
756
  balances: dict[str, int] = {USDC_TOKEN_ID: 0, WSTETH_TOKEN_ID: 0}
753
757
 
754
- async def mock_get_balance(*, token_id: str, wallet_address: str):
758
+ async def mock_get_balance(*, query: str, wallet_address: str):
759
+ token_id = query if isinstance(query, str) else (query or {}).get("token_id")
755
760
  return (True, balances.get(token_id, 0))
756
761
 
757
762
  strategy.balance_adapter.get_balance = AsyncMock(side_effect=mock_get_balance)
@@ -839,7 +844,8 @@ async def test_partial_liquidate_uses_usdc_collateral_when_no_wsteth_excess(stra
839
844
 
840
845
  balances: dict[str, int] = {USDC_TOKEN_ID: 0}
841
846
 
842
- async def mock_get_balance(*, token_id: str, wallet_address: str):
847
+ async def mock_get_balance(*, query: str, wallet_address: str):
848
+ token_id = query if isinstance(query, str) else (query or {}).get("token_id")
843
849
  return (True, balances.get(token_id, 0))
844
850
 
845
851
  strategy.balance_adapter.get_balance = AsyncMock(side_effect=mock_get_balance)
@@ -62,7 +62,7 @@ Transactions are scoped to the strategy wallet and Enso Router approval/swap cal
62
62
  ### Withdraw
63
63
 
64
64
  - Requires a prior deposit (the strategy tracks `self.DEPOSIT_USDC`).
65
- - Reads the pool balance via `BalanceAdapter.get_pool_balance`, unwinds via BRAP swaps back to USDC, and moves USDC from the strategy wallet to the main wallet via `BalanceAdapter.move_from_strategy_wallet_to_main_wallet`.
65
+ - Reads the pool balance via `BalanceAdapter.get_balance` (with pool address and chain_id), unwinds via BRAP swaps back to USDC, and moves USDC from the strategy wallet to the main wallet via `BalanceAdapter.move_from_strategy_wallet_to_main_wallet`.
66
66
  - Updates the ledger and clears cached pool state.
67
67
 
68
68
  ## Running locally
@@ -71,7 +71,7 @@ Transactions are scoped to the strategy wallet and Enso Router approval/swap cal
71
71
  # Install dependencies
72
72
  poetry install
73
73
 
74
- # Generate main wallet (writes wallets.json)
74
+ # Generate main wallet (writes config.json)
75
75
  # Creates a main wallet (or use 'just create-strategy' which auto-creates wallets)
76
76
  poetry run python wayfinder_paths/scripts/make_wallets.py -n 1
77
77
 
@@ -86,4 +86,4 @@ poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --ac
86
86
  poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --action update --config $(pwd)/config.json
87
87
  ```
88
88
 
89
- Wallet addresses are auto-populated from `wallets.json` when you run `wayfinder_paths/scripts/make_wallets.py`. Set `NETWORK=testnet` in `config.json` to dry-run operations against mocked services.
89
+ Wallet addresses are auto-populated from `config.json` when you run `wayfinder_paths/scripts/make_wallets.py`. Set `NETWORK=testnet` in `config.json` to dry-run operations against mocked services.
@@ -65,6 +65,7 @@ class StablecoinYieldStrategy(Strategy):
65
65
  f"Continuously optimizes positions for maximum stable yield while avoiding impermanent loss. "
66
66
  f"Min: {MIN_AMOUNT_USDC} USDC + ETH gas. Filters for ${MIN_TVL:,}+ TVL protocols."
67
67
  ),
68
+ risk_description=f"Protocol risk is always present when engaging with DeFi strategies, this includes underlying DeFi protocols and Wayfinder itself. Additional risks include temporary yield fluctuations, gas costs during rebalancing, and potential brief capital lock-up during protocol transitions. Strategy filters for protocols with a minimum TVL of ${MIN_TVL:,} to ensure low-risk exposure.",
68
69
  gas_token_symbol="ETH",
69
70
  gas_token_id="ethereum-base",
70
71
  deposit_token_id="usd-coin-base",
@@ -156,9 +157,8 @@ class StablecoinYieldStrategy(Strategy):
156
157
  main_wallet: dict[str, Any] | None = None,
157
158
  strategy_wallet: dict[str, Any] | None = None,
158
159
  web3_service=None,
159
- api_key: str | None = None,
160
160
  ):
161
- super().__init__(api_key=api_key)
161
+ super().__init__()
162
162
  merged_config: dict[str, Any] = dict(config or {})
163
163
  if main_wallet is not None:
164
164
  merged_config["main_wallet"] = main_wallet
@@ -270,7 +270,7 @@ class StablecoinYieldStrategy(Strategy):
270
270
  for token_id in self.tracked_token_ids:
271
271
  try:
272
272
  success, balance_wei = await self.balance_adapter.get_balance(
273
- token_id=token_id,
273
+ query=token_id,
274
274
  wallet_address=strategy_address,
275
275
  )
276
276
  if success and balance_wei:
@@ -303,8 +303,8 @@ class StablecoinYieldStrategy(Strategy):
303
303
  success, deposit_data = await self.ledger_adapter.get_strategy_net_deposit(
304
304
  wallet_address=strategy_address,
305
305
  )
306
- if success:
307
- self.DEPOSIT_USDC = deposit_data.get("net_deposit", 0)
306
+ if success and deposit_data is not None:
307
+ self.DEPOSIT_USDC = float(deposit_data)
308
308
  logger.info(f"Strategy net deposit: {self.DEPOSIT_USDC} USDC")
309
309
  else:
310
310
  logger.error(f"Failed to fetch strategy net deposit: {deposit_data}")
@@ -359,8 +359,8 @@ class StablecoinYieldStrategy(Strategy):
359
359
  f"Gas token loaded: {gas_token_data.get('symbol', 'Unknown')}"
360
360
  )
361
361
  # Track gas token (but don't count it as a strategy asset)
362
- if self.gas_token.get("id"):
363
- self._track_token(self.gas_token.get("id"))
362
+ if self.gas_token.get("token_id"):
363
+ self._track_token(self.gas_token.get("token_id"))
364
364
  else:
365
365
  logger.warning("Failed to fetch gas token info, using empty dict")
366
366
  self.gas_token = {}
@@ -427,35 +427,46 @@ class StablecoinYieldStrategy(Strategy):
427
427
  self._track_token(token_info.get("token_id"))
428
428
 
429
429
  success, reports = await self.pool_adapter.get_pools_by_ids(
430
- pool_ids=[self.current_pool.get("token_id")],
431
- merge_external=False,
430
+ pool_ids=[self.current_pool.get("token_id")]
432
431
  )
433
432
  if success and reports.get("pools"):
434
433
  self.current_pool_data = reports.get("pools", [])[0]
435
434
 
436
- identifiers = []
435
+ pool_ids = []
437
436
  pool_id = self.current_pool.get("token_id", None)
438
437
  if isinstance(pool_id, str):
439
- identifiers.append(pool_id)
438
+ pool_ids.append(pool_id)
440
439
 
441
440
  pool_address = self.current_pool.get("address", None)
442
441
  pool_chain = self.current_pool.get("chain", None)
443
442
  chain_code = ((pool_chain or {}).get("code")) or None
444
443
  if isinstance(pool_address, str) and isinstance(chain_code, str):
445
- identifiers.append(f"{chain_code.lower()}_{pool_address.lower()}")
444
+ pool_ids.append(f"{chain_code.lower()}_{pool_address.lower()}")
446
445
 
447
446
  llama_report = None
448
- if identifiers:
449
- success, llama_reports = await self.pool_adapter.get_llama_reports(
450
- identifiers=identifiers
447
+ if pool_ids:
448
+ success, pool_list_response = await self.pool_adapter.get_pools_by_ids(
449
+ pool_ids=pool_ids
451
450
  )
452
- if success:
453
- for identifier in identifiers:
451
+ if success and isinstance(pool_list_response, dict):
452
+ pools = pool_list_response.get("pools", [])
453
+ # Search for matching pool by id or constructed identifier
454
+ for identifier in pool_ids:
454
455
  if not isinstance(identifier, str):
455
456
  continue
456
- report = llama_reports.get(identifier.lower(), None)
457
- if report:
458
- llama_report = report
457
+ identifier_lower = identifier.lower()
458
+ for pool in pools:
459
+ pool_id = pool.get("id", "").lower()
460
+ pool_address = pool.get("address", "").lower()
461
+ pool_chain_code = pool.get("chain_code", "").lower()
462
+ constructed_id = f"{pool_chain_code}_{pool_address}"
463
+ if (
464
+ pool_id == identifier_lower
465
+ or constructed_id == identifier_lower
466
+ ):
467
+ llama_report = pool
468
+ break
469
+ if llama_report:
459
470
  break
460
471
 
461
472
  if self.current_pool_data is None and llama_report:
@@ -464,14 +475,21 @@ class StablecoinYieldStrategy(Strategy):
464
475
  "llama_report": llama_report,
465
476
  }
466
477
 
467
- if llama_report and llama_report.get("llama_combined_apy_pct") is not None:
478
+ if llama_report and llama_report.get("combined_apy_pct") is not None:
468
479
  self.current_combined_apy_pct = (
469
- llama_report.get("llama_combined_apy_pct", 0) / 100
480
+ llama_report.get("combined_apy_pct", 0) / 100
470
481
  )
471
- elif llama_report and llama_report.get("llama_apy_pct") is not None:
472
- self.current_combined_apy_pct = llama_report.get("llama_apy_pct", 0) / 100
482
+ elif llama_report and llama_report.get("apy") is not None:
483
+ self.current_combined_apy_pct = llama_report.get("apy", 0) / 100
473
484
  elif self.current_pool_data:
474
- self.current_combined_apy_pct = self.current_pool_data.get("apy", 0)
485
+ apy_pct = self.current_pool_data.get("combined_apy_pct")
486
+ if apy_pct is not None:
487
+ self.current_combined_apy_pct = float(apy_pct) / 100
488
+ else:
489
+ apy_val = self.current_pool_data.get("apy", 0)
490
+ self.current_combined_apy_pct = (
491
+ float(apy_val) / 100 if apy_val is not None else 0
492
+ )
475
493
 
476
494
  pool_address = self.current_pool.get("address")
477
495
  chain_id = self.current_pool.get("chain", {}).get("id")
@@ -486,10 +504,10 @@ class StablecoinYieldStrategy(Strategy):
486
504
  (
487
505
  success,
488
506
  current_pool_balance_raw,
489
- ) = await self.balance_adapter.get_pool_balance(
490
- pool_address=pool_address,
507
+ ) = await self.balance_adapter.get_balance(
508
+ query=pool_address,
509
+ wallet_address=user_address,
491
510
  chain_id=chain_id,
492
- user_address=user_address,
493
511
  )
494
512
  self.current_pool_balance = current_pool_balance_raw if success else 0
495
513
  except Exception as e:
@@ -525,8 +543,8 @@ class StablecoinYieldStrategy(Strategy):
525
543
  self.current_pool_balance = inferred_balance
526
544
  if inferred_entry:
527
545
  self.current_pool_data = inferred_entry
528
- llama_combined = inferred_entry.get("llama_combined_apy_pct")
529
- llama_apy = inferred_entry.get("llama_apy_pct")
546
+ llama_combined = inferred_entry.get("combined_apy_pct")
547
+ llama_apy = inferred_entry.get("apy")
530
548
  if llama_combined is not None:
531
549
  self.current_combined_apy_pct = float(llama_combined) / 100
532
550
  elif llama_apy is not None:
@@ -535,7 +553,7 @@ class StablecoinYieldStrategy(Strategy):
535
553
 
536
554
  if self.usdc_token_info:
537
555
  status, raw_balance = await self.balance_adapter.get_balance(
538
- token_id=self.usdc_token_info.get("token_id"),
556
+ query=self.usdc_token_info.get("token_id"),
539
557
  wallet_address=self._get_strategy_wallet_address(),
540
558
  )
541
559
  if not status or not raw_balance:
@@ -578,7 +596,7 @@ class StablecoinYieldStrategy(Strategy):
578
596
  await self._refresh_tracked_balances()
579
597
 
580
598
  usdc_token_id = self.usdc_token_info.get("token_id")
581
- gas_token_id = self.gas_token.get("id") if self.gas_token else None
599
+ gas_token_id = self.gas_token.get("token_id") if self.gas_token else None
582
600
 
583
601
  best_token_id = None
584
602
  best_balance_wei = 0
@@ -609,7 +627,7 @@ class StablecoinYieldStrategy(Strategy):
609
627
  strategy_address = self._get_strategy_wallet_address()
610
628
  try:
611
629
  success, onchain_balance = await self.balance_adapter.get_balance(
612
- token_id=token.get("token_id"),
630
+ query=token.get("token_id"),
613
631
  wallet_address=strategy_address,
614
632
  )
615
633
  if success and onchain_balance:
@@ -635,7 +653,7 @@ class StablecoinYieldStrategy(Strategy):
635
653
  token_id = balance.get("token_id")
636
654
  if (
637
655
  isinstance(token_id, str)
638
- and token_id.lower() == self.gas_token.get("id", "").lower()
656
+ and token_id.lower() == self.gas_token.get("token_id", "").lower()
639
657
  ):
640
658
  return True
641
659
 
@@ -680,7 +698,7 @@ class StablecoinYieldStrategy(Strategy):
680
698
  "address": token_info.get("address"),
681
699
  "chain": token_info.get("chain"),
682
700
  }
683
- gas_token_id = self.gas_token.get("id")
701
+ gas_token_id = self.gas_token.get("token_id")
684
702
  logger.info(
685
703
  f"Current pool set to: {token_info.get('symbol')} on {token_info.get('chain', {}).get('name')}"
686
704
  )
@@ -692,7 +710,7 @@ class StablecoinYieldStrategy(Strategy):
692
710
  main_usdc_status,
693
711
  main_usdc_balance,
694
712
  ) = await self.balance_adapter.get_balance(
695
- token_id=token_info.get("token_id"),
713
+ query=token_info.get("token_id"),
696
714
  wallet_address=self._get_main_wallet_address(),
697
715
  )
698
716
  if main_usdc_status and main_usdc_balance is not None:
@@ -737,7 +755,7 @@ class StablecoinYieldStrategy(Strategy):
737
755
  _,
738
756
  main_gas_raw,
739
757
  ) = await self.balance_adapter.get_balance(
740
- token_id=gas_token_id,
758
+ query=gas_token_id,
741
759
  wallet_address=self._get_main_wallet_address(),
742
760
  )
743
761
  main_gas_int = (
@@ -762,14 +780,14 @@ class StablecoinYieldStrategy(Strategy):
762
780
  _,
763
781
  main_gas_raw,
764
782
  ) = await self.balance_adapter.get_balance(
765
- token_id=gas_token_id,
783
+ query=gas_token_id,
766
784
  wallet_address=self._get_main_wallet_address(),
767
785
  )
768
786
  (
769
787
  _,
770
788
  strategy_gas_raw,
771
789
  ) = await self.balance_adapter.get_balance(
772
- token_id=gas_token_id,
790
+ query=gas_token_id,
773
791
  wallet_address=self._get_strategy_wallet_address(),
774
792
  )
775
793
  main_gas_int = (
@@ -895,10 +913,10 @@ class StablecoinYieldStrategy(Strategy):
895
913
  (
896
914
  _,
897
915
  self.current_pool_balance,
898
- ) = await self.balance_adapter.get_pool_balance(
899
- pool_address=self.current_pool.get("address"),
916
+ ) = await self.balance_adapter.get_balance(
917
+ query=self.current_pool.get("address"),
918
+ wallet_address=self._get_strategy_wallet_address(),
900
919
  chain_id=self.current_pool.get("chain").get("id"),
901
- user_address=self._get_strategy_wallet_address(),
902
920
  )
903
921
  logger.info(f"Current pool balance: {self.current_pool_balance}")
904
922
  except Exception as e:
@@ -931,8 +949,8 @@ class StablecoinYieldStrategy(Strategy):
931
949
  )
932
950
  if (
933
951
  success
934
- and quotes.get("quotes")
935
- and quotes.get("quotes").get("best_quote")
952
+ and isinstance(quotes, dict)
953
+ and quotes.get("best_quote")
936
954
  ):
937
955
  logger.info("Successfully obtained swap quote")
938
956
  break
@@ -941,7 +959,7 @@ class StablecoinYieldStrategy(Strategy):
941
959
  if attempt == 3: # Last attempt
942
960
  logger.error("All quote attempts failed")
943
961
 
944
- best_quote = quotes.get("quotes").get("best_quote")
962
+ best_quote = quotes.get("best_quote") if isinstance(quotes, dict) else None
945
963
  if not best_quote:
946
964
  return (
947
965
  False,
@@ -998,7 +1016,7 @@ class StablecoinYieldStrategy(Strategy):
998
1016
  if self.usdc_token_info.get("token_id") in withdrawn_token_ids:
999
1017
  pass
1000
1018
  status, raw_balance = await self.balance_adapter.get_balance(
1001
- token_id=self.usdc_token_info.get("token_id"),
1019
+ query=self.usdc_token_info.get("token_id"),
1002
1020
  wallet_address=self._get_strategy_wallet_address(),
1003
1021
  )
1004
1022
  if not status or not raw_balance:
@@ -1025,9 +1043,9 @@ class StablecoinYieldStrategy(Strategy):
1025
1043
  )
1026
1044
  withdrawn_token_ids.add(self.usdc_token_info.get("token_id"))
1027
1045
 
1028
- if self.gas_token and self.gas_token.get("id") not in withdrawn_token_ids:
1046
+ if self.gas_token and self.gas_token.get("token_id") not in withdrawn_token_ids:
1029
1047
  status, raw_gas = await self.balance_adapter.get_balance(
1030
- token_id=self.gas_token.get("id"),
1048
+ query=self.gas_token.get("token_id"),
1031
1049
  wallet_address=self._get_strategy_wallet_address(),
1032
1050
  )
1033
1051
  if status and raw_gas:
@@ -1039,7 +1057,7 @@ class StablecoinYieldStrategy(Strategy):
1039
1057
  move_gas_status,
1040
1058
  move_gas_message,
1041
1059
  ) = await self.balance_adapter.move_from_strategy_wallet_to_main_wallet(
1042
- self.gas_token.get("id"),
1060
+ self.gas_token.get("token_id"),
1043
1061
  gas_amount,
1044
1062
  strategy_name=self.name,
1045
1063
  )
@@ -1051,7 +1069,7 @@ class StablecoinYieldStrategy(Strategy):
1051
1069
  float(gas_amount),
1052
1070
  )
1053
1071
  )
1054
- withdrawn_token_ids.add(self.gas_token.get("id"))
1072
+ withdrawn_token_ids.add(self.gas_token.get("token_id"))
1055
1073
 
1056
1074
  self.DEPOSIT_USDC = 0
1057
1075
  self.current_pool_balance = 0
@@ -1206,10 +1224,17 @@ class StablecoinYieldStrategy(Strategy):
1206
1224
  else:
1207
1225
  self.current_pool_data = None
1208
1226
  if self.current_pool_data:
1209
- self.current_combined_apy_pct = self.current_pool_data.get("apy", 0)
1227
+ apy_pct = self.current_pool_data.get("combined_apy_pct")
1228
+ if apy_pct is not None:
1229
+ self.current_combined_apy_pct = float(apy_pct) / 100
1230
+ else:
1231
+ apy_val = self.current_pool_data.get("apy", 0)
1232
+ self.current_combined_apy_pct = (
1233
+ float(apy_val) / 100 if apy_val is not None else 0
1234
+ )
1210
1235
  else:
1211
1236
  self.current_combined_apy_pct = (
1212
- target_pool_data.get("llama_combined_apy_pct", 0) / 100
1237
+ target_pool_data.get("combined_apy_pct", 0) / 100
1213
1238
  if target_pool_data
1214
1239
  else 0
1215
1240
  )
@@ -1242,10 +1267,10 @@ class StablecoinYieldStrategy(Strategy):
1242
1267
  (
1243
1268
  _,
1244
1269
  refreshed_pool_balance,
1245
- ) = await self.balance_adapter.get_pool_balance(
1246
- pool_address=pool.get("address"),
1270
+ ) = await self.balance_adapter.get_balance(
1271
+ query=pool.get("address"),
1272
+ wallet_address=strategy_address,
1247
1273
  chain_id=pool.get("chain").get("id"),
1248
- user_address=strategy_address,
1249
1274
  )
1250
1275
  self.current_pool_balance = int(refreshed_pool_balance)
1251
1276
  except Exception:
@@ -1259,7 +1284,7 @@ class StablecoinYieldStrategy(Strategy):
1259
1284
  target_token_id = target_token.get("token_id")
1260
1285
  target_chain = target_token.get("chain").get("code", "").lower()
1261
1286
  target_address = target_token.get("address", "").lower()
1262
- gas_token_id = self.gas_token.get("id") if self.gas_token else None
1287
+ gas_token_id = self.gas_token.get("token_id") if self.gas_token else None
1263
1288
 
1264
1289
  # Swap all non-target, non-gas tokens to the target
1265
1290
  for token_id, balance_wei in list(self.tracked_balances.items()):
@@ -1278,7 +1303,7 @@ class StablecoinYieldStrategy(Strategy):
1278
1303
  # Get fresh balance to ensure accuracy
1279
1304
  try:
1280
1305
  success, fresh_balance = await self.balance_adapter.get_balance(
1281
- token_id=token_id,
1306
+ query=token_id,
1282
1307
  wallet_address=self._get_strategy_wallet_address(),
1283
1308
  )
1284
1309
  if not success or not fresh_balance or int(fresh_balance) <= 0:
@@ -1318,7 +1343,7 @@ class StablecoinYieldStrategy(Strategy):
1318
1343
  # Refresh target token balance
1319
1344
  try:
1320
1345
  success, target_balance = await self.balance_adapter.get_balance(
1321
- token_id=target_token_id,
1346
+ query=target_token_id,
1322
1347
  wallet_address=self._get_strategy_wallet_address(),
1323
1348
  )
1324
1349
  if success and target_balance:
@@ -1335,7 +1360,7 @@ class StablecoinYieldStrategy(Strategy):
1335
1360
 
1336
1361
  required_gas = int(self.MIN_GAS * (10 ** self.gas_token.get("decimals")))
1337
1362
  _, current_gas = await self.balance_adapter.get_balance(
1338
- token_id=self.gas_token.get("id"),
1363
+ query=self.gas_token.get("token_id"),
1339
1364
  wallet_address=strategy_address,
1340
1365
  )
1341
1366
  if current_gas >= required_gas:
@@ -1395,7 +1420,11 @@ class StablecoinYieldStrategy(Strategy):
1395
1420
  if not success:
1396
1421
  return 0.0
1397
1422
 
1398
- best_quote = exit_quotes.get("quotes").get("best_quote")
1423
+ best_quote = (
1424
+ exit_quotes.get("best_quote") if isinstance(exit_quotes, dict) else None
1425
+ )
1426
+ if not best_quote:
1427
+ return None
1399
1428
  current_pool_usd_value = best_quote.get("output_amount")
1400
1429
 
1401
1430
  return float(
@@ -1407,7 +1436,7 @@ class StablecoinYieldStrategy(Strategy):
1407
1436
  # Refresh tracked balances
1408
1437
  await self._refresh_tracked_balances()
1409
1438
 
1410
- gas_token_id = self.gas_token.get("id") if self.gas_token else None
1439
+ gas_token_id = self.gas_token.get("token_id") if self.gas_token else None
1411
1440
  results = []
1412
1441
 
1413
1442
  for token_id, balance_wei in self.tracked_balances.items():
@@ -1440,21 +1469,24 @@ class StablecoinYieldStrategy(Strategy):
1440
1469
  return results
1441
1470
 
1442
1471
  async def _find_best_pool(self) -> tuple[bool, dict[str, Any]]:
1443
- success, llama_data = await self.pool_adapter.get_llama_matches()
1472
+ chain_id = (self.usdc_token_info or {}).get("chain", {}).get("id")
1473
+ if chain_id is None:
1474
+ chain_id = 8453
1475
+ success, llama_data = await self.pool_adapter.get_pools(chain_id=chain_id)
1444
1476
  if not success:
1445
1477
  return False, {"message": f"Failed to fetch Llama data: {llama_data}"}
1446
1478
 
1447
1479
  llama_pools = [
1448
1480
  pool
1449
1481
  for pool in llama_data.get("matches", [])
1450
- if pool.get("llama_stablecoin")
1451
- and pool.get("llama_il_risk") == "no"
1452
- and pool.get("llama_tvl_usd") > self.MIN_TVL
1453
- and pool.get("llama_apy_pct") > self.DUST_APY
1482
+ if pool.get("stablecoin")
1483
+ and pool.get("ilRisk") == "no"
1484
+ and pool.get("tvlUsd") > self.MIN_TVL
1485
+ and pool.get("combined_apy_pct") > self.DUST_APY
1454
1486
  and pool.get("network", "").lower() in self.SUPPORTED_NETWORK_CODES
1455
1487
  ]
1456
1488
  llama_pools = sorted(
1457
- llama_pools, key=lambda pool: pool.get("llama_apy_pct"), reverse=True
1489
+ llama_pools, key=lambda pool: pool.get("combined_apy_pct"), reverse=True
1458
1490
  )
1459
1491
  if not llama_pools:
1460
1492
  return False, {"message": "No suitable pools found."}
@@ -1469,11 +1501,11 @@ class StablecoinYieldStrategy(Strategy):
1469
1501
  )
1470
1502
  if not target_status and candidate.get("token_id"):
1471
1503
  target_status, target_pool = await self.token_adapter.get_token(
1472
- token_id=candidate.get("token_id")
1504
+ query=candidate.get("token_id")
1473
1505
  )
1474
1506
  if not target_status and candidate.get("pool_id"):
1475
1507
  target_status, target_pool = await self.token_adapter.get_token(
1476
- token_id=candidate.get("pool_id")
1508
+ query=candidate.get("pool_id")
1477
1509
  )
1478
1510
  if not target_status:
1479
1511
  continue
@@ -1515,7 +1547,8 @@ class StablecoinYieldStrategy(Strategy):
1515
1547
  return None
1516
1548
 
1517
1549
  try:
1518
- combined_apy_pct = pool_data.get("llama_combined_apy_pct") / 100
1550
+ apy_pct = pool_data.get("combined_apy_pct") or pool_data.get("apy") or 0
1551
+ combined_apy_pct = float(apy_pct) / 100
1519
1552
  success, quotes = await self.brap_adapter.get_swap_quote(
1520
1553
  from_token_address=current_token.get("address"),
1521
1554
  to_token_address=token.get("address"),
@@ -1527,10 +1560,9 @@ class StablecoinYieldStrategy(Strategy):
1527
1560
  )
1528
1561
  if not success:
1529
1562
  return None
1530
- quotes_data = quotes.get("quotes") if isinstance(quotes, dict) else None
1531
- if not isinstance(quotes_data, dict):
1563
+ if not isinstance(quotes, dict):
1532
1564
  return None
1533
- best_quote = quotes_data.get("best_quote")
1565
+ best_quote = quotes.get("best_quote")
1534
1566
  if not best_quote:
1535
1567
  return None
1536
1568
 
@@ -1582,7 +1614,7 @@ class StablecoinYieldStrategy(Strategy):
1582
1614
  async def _status(self) -> StatusDict:
1583
1615
  # Get ETH gas balance
1584
1616
  gas_success, gas_balance_wei = await self.balance_adapter.get_balance(
1585
- token_id=self.gas_token.get("id"),
1617
+ query=self.gas_token.get("token_id"),
1586
1618
  wallet_address=self._get_strategy_wallet_address(),
1587
1619
  )
1588
1620
  gas_balance = (
@@ -1611,7 +1643,7 @@ class StablecoinYieldStrategy(Strategy):
1611
1643
 
1612
1644
  # Calculate total value from tracked non-gas balances
1613
1645
  total_value = 0.0
1614
- gas_token_id = self.gas_token.get("id") if self.gas_token else None
1646
+ gas_token_id = self.gas_token.get("token_id") if self.gas_token else None
1615
1647
 
1616
1648
  for token_id, balance_wei in self.tracked_balances.items():
1617
1649
  if token_id == gas_token_id:
@@ -1680,7 +1712,7 @@ class StablecoinYieldStrategy(Strategy):
1680
1712
 
1681
1713
  usdc_token_id = self.usdc_token_info.get("token_id")
1682
1714
  usdc_decimals = self.usdc_token_info.get("decimals")
1683
- gas_token_id = self.gas_token.get("id") if self.gas_token else None
1715
+ gas_token_id = self.gas_token.get("token_id") if self.gas_token else None
1684
1716
 
1685
1717
  # Check current USDC balance
1686
1718
  available_usdc_wei = self.tracked_balances.get(usdc_token_id, 0)
@@ -1745,7 +1777,7 @@ class StablecoinYieldStrategy(Strategy):
1745
1777
 
1746
1778
  # Refresh USDC balance after swaps
1747
1779
  success, usdc_wei = await self.balance_adapter.get_balance(
1748
- token_id=usdc_token_id,
1780
+ query=usdc_token_id,
1749
1781
  wallet_address=self._get_strategy_wallet_address(),
1750
1782
  )
1751
1783
  if success and usdc_wei:
@@ -1790,7 +1822,7 @@ class StablecoinYieldStrategy(Strategy):
1790
1822
 
1791
1823
  # Refresh USDC balance again
1792
1824
  success, usdc_wei = await self.balance_adapter.get_balance(
1793
- token_id=usdc_token_id,
1825
+ query=usdc_token_id,
1794
1826
  wallet_address=self._get_strategy_wallet_address(),
1795
1827
  )
1796
1828
  if success and usdc_wei: