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.
- wayfinder_paths/__init__.py +0 -4
- wayfinder_paths/adapters/balance_adapter/README.md +0 -1
- wayfinder_paths/adapters/balance_adapter/adapter.py +313 -167
- wayfinder_paths/adapters/balance_adapter/manifest.yaml +8 -0
- wayfinder_paths/adapters/balance_adapter/test_adapter.py +41 -124
- wayfinder_paths/adapters/boros_adapter/__init__.py +17 -0
- wayfinder_paths/adapters/boros_adapter/adapter.py +1574 -0
- wayfinder_paths/adapters/boros_adapter/client.py +476 -0
- wayfinder_paths/adapters/boros_adapter/manifest.yaml +10 -0
- wayfinder_paths/adapters/boros_adapter/parsers.py +88 -0
- wayfinder_paths/adapters/boros_adapter/test_adapter.py +460 -0
- wayfinder_paths/adapters/boros_adapter/test_golden.py +156 -0
- wayfinder_paths/adapters/boros_adapter/types.py +70 -0
- wayfinder_paths/adapters/boros_adapter/utils.py +85 -0
- wayfinder_paths/adapters/brap_adapter/README.md +22 -75
- wayfinder_paths/adapters/brap_adapter/adapter.py +187 -576
- wayfinder_paths/adapters/brap_adapter/examples.json +21 -140
- wayfinder_paths/adapters/brap_adapter/manifest.yaml +9 -0
- wayfinder_paths/adapters/brap_adapter/test_adapter.py +6 -234
- wayfinder_paths/adapters/hyperlend_adapter/adapter.py +180 -92
- wayfinder_paths/adapters/hyperlend_adapter/manifest.yaml +9 -0
- wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +82 -14
- wayfinder_paths/adapters/hyperliquid_adapter/__init__.py +2 -9
- wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +586 -61
- wayfinder_paths/adapters/hyperliquid_adapter/executor.py +47 -68
- wayfinder_paths/adapters/hyperliquid_adapter/manifest.yaml +14 -0
- wayfinder_paths/adapters/hyperliquid_adapter/paired_filler.py +2 -3
- wayfinder_paths/adapters/hyperliquid_adapter/test_adapter.py +17 -21
- wayfinder_paths/adapters/hyperliquid_adapter/test_adapter_live.py +3 -6
- wayfinder_paths/adapters/hyperliquid_adapter/test_executor.py +4 -8
- wayfinder_paths/adapters/hyperliquid_adapter/test_utils.py +2 -2
- wayfinder_paths/adapters/ledger_adapter/README.md +4 -1
- wayfinder_paths/adapters/ledger_adapter/adapter.py +3 -3
- wayfinder_paths/adapters/ledger_adapter/manifest.yaml +7 -0
- wayfinder_paths/adapters/ledger_adapter/test_adapter.py +1 -2
- wayfinder_paths/adapters/moonwell_adapter/adapter.py +649 -547
- wayfinder_paths/adapters/moonwell_adapter/manifest.yaml +14 -0
- wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +160 -239
- wayfinder_paths/adapters/multicall_adapter/__init__.py +7 -0
- wayfinder_paths/adapters/multicall_adapter/adapter.py +166 -0
- wayfinder_paths/adapters/multicall_adapter/manifest.yaml +5 -0
- wayfinder_paths/adapters/multicall_adapter/test_adapter.py +97 -0
- wayfinder_paths/adapters/pendle_adapter/README.md +102 -0
- wayfinder_paths/adapters/pendle_adapter/__init__.py +7 -0
- wayfinder_paths/adapters/pendle_adapter/adapter.py +1992 -0
- wayfinder_paths/adapters/pendle_adapter/examples.json +11 -0
- wayfinder_paths/adapters/pendle_adapter/manifest.yaml +21 -0
- wayfinder_paths/adapters/pendle_adapter/test_adapter.py +666 -0
- wayfinder_paths/adapters/pool_adapter/manifest.yaml +6 -0
- wayfinder_paths/adapters/token_adapter/adapter.py +14 -0
- wayfinder_paths/adapters/token_adapter/examples.json +0 -4
- wayfinder_paths/adapters/token_adapter/manifest.yaml +7 -0
- wayfinder_paths/conftest.py +24 -17
- wayfinder_paths/core/__init__.py +0 -3
- wayfinder_paths/core/adapters/BaseAdapter.py +0 -25
- wayfinder_paths/core/adapters/models.py +17 -7
- wayfinder_paths/core/clients/BRAPClient.py +4 -1
- wayfinder_paths/core/clients/ClientManager.py +0 -7
- wayfinder_paths/core/clients/LedgerClient.py +196 -172
- wayfinder_paths/core/clients/TokenClient.py +47 -1
- wayfinder_paths/core/clients/WayfinderClient.py +1 -3
- wayfinder_paths/core/clients/__init__.py +0 -5
- wayfinder_paths/core/clients/protocols.py +21 -35
- wayfinder_paths/core/clients/test_ledger_client.py +448 -0
- wayfinder_paths/core/config.py +10 -162
- wayfinder_paths/core/constants/__init__.py +73 -2
- wayfinder_paths/core/constants/base.py +8 -17
- wayfinder_paths/core/constants/chains.py +36 -0
- wayfinder_paths/core/constants/contracts.py +52 -0
- wayfinder_paths/core/constants/erc20_abi.py +0 -1
- wayfinder_paths/core/constants/hyperlend_abi.py +0 -4
- wayfinder_paths/core/constants/hyperliquid.py +16 -0
- wayfinder_paths/core/constants/moonwell_abi.py +0 -15
- wayfinder_paths/core/constants/tokens.py +9 -0
- wayfinder_paths/core/engine/manifest.py +66 -0
- wayfinder_paths/core/strategies/Strategy.py +0 -71
- wayfinder_paths/core/strategies/__init__.py +10 -1
- wayfinder_paths/core/strategies/opa_loop.py +167 -0
- wayfinder_paths/core/utils/evm_helpers.py +5 -15
- wayfinder_paths/core/utils/test_transaction.py +289 -0
- wayfinder_paths/core/utils/tokens.py +28 -0
- wayfinder_paths/core/utils/transaction.py +57 -8
- wayfinder_paths/core/utils/web3.py +8 -3
- wayfinder_paths/mcp/__init__.py +5 -0
- wayfinder_paths/mcp/preview.py +185 -0
- wayfinder_paths/mcp/scripting.py +84 -0
- wayfinder_paths/mcp/server.py +52 -0
- wayfinder_paths/mcp/state/profile_store.py +195 -0
- wayfinder_paths/mcp/state/store.py +89 -0
- wayfinder_paths/mcp/test_scripting.py +267 -0
- wayfinder_paths/mcp/tools/__init__.py +0 -0
- wayfinder_paths/mcp/tools/balances.py +290 -0
- wayfinder_paths/mcp/tools/discovery.py +158 -0
- wayfinder_paths/mcp/tools/execute.py +770 -0
- wayfinder_paths/mcp/tools/hyperliquid.py +931 -0
- wayfinder_paths/mcp/tools/quotes.py +288 -0
- wayfinder_paths/mcp/tools/run_script.py +286 -0
- wayfinder_paths/mcp/tools/strategies.py +188 -0
- wayfinder_paths/mcp/tools/tokens.py +46 -0
- wayfinder_paths/mcp/tools/wallets.py +354 -0
- wayfinder_paths/mcp/utils.py +129 -0
- wayfinder_paths/policies/enso.py +1 -2
- wayfinder_paths/policies/hyper_evm.py +6 -3
- wayfinder_paths/policies/hyperlend.py +1 -2
- wayfinder_paths/policies/hyperliquid.py +1 -1
- wayfinder_paths/policies/lifi.py +18 -0
- wayfinder_paths/policies/moonwell.py +12 -7
- wayfinder_paths/policies/prjx.py +1 -3
- wayfinder_paths/policies/util.py +8 -2
- wayfinder_paths/run_strategy.py +97 -300
- wayfinder_paths/strategies/basis_trading_strategy/constants.py +3 -1
- wayfinder_paths/strategies/basis_trading_strategy/strategy.py +47 -133
- wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +24 -53
- wayfinder_paths/strategies/boros_hype_strategy/__init__.py +3 -0
- wayfinder_paths/strategies/boros_hype_strategy/boros_ops_mixin.py +450 -0
- wayfinder_paths/strategies/boros_hype_strategy/constants.py +255 -0
- wayfinder_paths/strategies/boros_hype_strategy/examples.json +37 -0
- wayfinder_paths/strategies/boros_hype_strategy/hyperevm_ops_mixin.py +114 -0
- wayfinder_paths/strategies/boros_hype_strategy/hyperliquid_ops_mixin.py +642 -0
- wayfinder_paths/strategies/boros_hype_strategy/manifest.yaml +36 -0
- wayfinder_paths/strategies/boros_hype_strategy/planner.py +460 -0
- wayfinder_paths/strategies/boros_hype_strategy/risk_ops_mixin.py +886 -0
- wayfinder_paths/strategies/boros_hype_strategy/snapshot_mixin.py +494 -0
- wayfinder_paths/strategies/boros_hype_strategy/strategy.py +1194 -0
- wayfinder_paths/strategies/boros_hype_strategy/test_planner_golden.py +374 -0
- wayfinder_paths/{templates/strategy → strategies/boros_hype_strategy}/test_strategy.py +99 -63
- wayfinder_paths/strategies/boros_hype_strategy/types.py +365 -0
- wayfinder_paths/strategies/boros_hype_strategy/withdraw_mixin.py +997 -0
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +15 -23
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +27 -62
- wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +84 -58
- wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/test_strategy.py +5 -15
- wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +69 -164
- wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +43 -76
- wayfinder_paths/tests/test_mcp_quote_swap.py +165 -0
- wayfinder_paths/tests/test_test_coverage.py +1 -4
- wayfinder_paths-0.1.24.dist-info/METADATA +378 -0
- wayfinder_paths-0.1.24.dist-info/RECORD +185 -0
- {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.24.dist-info}/WHEEL +1 -1
- wayfinder_paths/core/clients/WalletClient.py +0 -41
- wayfinder_paths/core/engine/StrategyJob.py +0 -110
- wayfinder_paths/core/services/test_local_evm_txn.py +0 -145
- wayfinder_paths/scripts/create_strategy.py +0 -139
- wayfinder_paths/scripts/make_wallets.py +0 -142
- wayfinder_paths/templates/adapter/README.md +0 -150
- wayfinder_paths/templates/adapter/adapter.py +0 -16
- wayfinder_paths/templates/adapter/examples.json +0 -8
- wayfinder_paths/templates/adapter/test_adapter.py +0 -30
- wayfinder_paths/templates/strategy/README.md +0 -186
- wayfinder_paths/templates/strategy/examples.json +0 -11
- wayfinder_paths/templates/strategy/strategy.py +0 -35
- wayfinder_paths/tests/test_smoke_manifest.py +0 -63
- wayfinder_paths-0.1.22.dist-info/METADATA +0 -355
- wayfinder_paths-0.1.22.dist-info/RECORD +0 -129
- /wayfinder_paths/{scripts → mcp/state}/__init__.py +0 -0
- {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
|
-
|
|
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("
|
|
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
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
)
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1712
|
+
token_id=usdc_token_id,
|
|
1808
1713
|
wallet_address=self._get_strategy_wallet_address(),
|
|
1809
1714
|
)
|
|
1810
1715
|
if success and usdc_wei:
|