wayfinder-paths 0.1.22__py3-none-any.whl → 0.1.23__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 +65 -169
- wayfinder_paths/adapters/balance_adapter/test_adapter.py +41 -113
- 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/test_adapter.py +6 -234
- wayfinder_paths/adapters/hyperlend_adapter/adapter.py +39 -86
- wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +5 -1
- wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +6 -5
- wayfinder_paths/adapters/ledger_adapter/README.md +4 -1
- wayfinder_paths/adapters/ledger_adapter/adapter.py +3 -3
- wayfinder_paths/adapters/moonwell_adapter/adapter.py +108 -198
- wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +37 -23
- wayfinder_paths/adapters/token_adapter/adapter.py +14 -0
- wayfinder_paths/core/__init__.py +0 -3
- wayfinder_paths/core/clients/BRAPClient.py +3 -0
- wayfinder_paths/core/clients/ClientManager.py +0 -7
- wayfinder_paths/core/clients/LedgerClient.py +196 -172
- wayfinder_paths/core/clients/WayfinderClient.py +0 -1
- wayfinder_paths/core/clients/__init__.py +0 -5
- wayfinder_paths/core/clients/protocols.py +0 -13
- wayfinder_paths/core/config.py +0 -164
- wayfinder_paths/core/constants/__init__.py +58 -2
- wayfinder_paths/core/constants/base.py +8 -22
- wayfinder_paths/core/constants/chains.py +36 -0
- wayfinder_paths/core/constants/contracts.py +39 -0
- wayfinder_paths/core/constants/tokens.py +9 -0
- wayfinder_paths/core/strategies/Strategy.py +0 -10
- wayfinder_paths/core/utils/evm_helpers.py +5 -15
- wayfinder_paths/core/utils/tokens.py +28 -0
- wayfinder_paths/core/utils/transaction.py +13 -7
- wayfinder_paths/core/utils/web3.py +5 -3
- 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/moonwell.py +12 -7
- wayfinder_paths/policies/prjx.py +1 -3
- 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 +19 -14
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +12 -11
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +20 -33
- wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +21 -18
- wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +69 -130
- wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +32 -42
- {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/METADATA +2 -3
- {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/RECORD +51 -60
- {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.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/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/templates/strategy/test_strategy.py +0 -166
- wayfinder_paths/tests/test_smoke_manifest.py +0 -63
- {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/LICENSE +0 -0
|
@@ -48,10 +48,9 @@ def strategy():
|
|
|
48
48
|
|
|
49
49
|
if hasattr(s, "balance_adapter") and s.balance_adapter:
|
|
50
50
|
# Mock balances: 1000 USDT0 (with 6 decimals) and 2 HYPE (with 18 decimals)
|
|
51
|
-
def get_balance_side_effect(
|
|
52
|
-
token_id =
|
|
53
|
-
|
|
54
|
-
)
|
|
51
|
+
def get_balance_side_effect(
|
|
52
|
+
*, wallet_address, token_id=None, token_address=None, chain_id=None
|
|
53
|
+
):
|
|
55
54
|
token_id_str = str(token_id).lower() if token_id else ""
|
|
56
55
|
if "usdt0" in token_id_str or token_id_str == "usdt0":
|
|
57
56
|
# 1000 USDT0 with 6 decimals = 1000 * 10^6 = 1000000000
|
|
@@ -145,9 +144,7 @@ def strategy():
|
|
|
145
144
|
)
|
|
146
145
|
|
|
147
146
|
if hasattr(s, "ledger_adapter") and s.ledger_adapter:
|
|
148
|
-
s.ledger_adapter.get_strategy_net_deposit = AsyncMock(
|
|
149
|
-
return_value=(True, {"net_deposit": 0})
|
|
150
|
-
)
|
|
147
|
+
s.ledger_adapter.get_strategy_net_deposit = AsyncMock(return_value=(True, 0.0))
|
|
151
148
|
s.ledger_adapter.get_strategy_transactions = AsyncMock(
|
|
152
149
|
return_value=(True, {"transactions": []})
|
|
153
150
|
)
|
|
@@ -155,46 +152,36 @@ def strategy():
|
|
|
155
152
|
if hasattr(s, "brap_adapter") and s.brap_adapter:
|
|
156
153
|
usdt0_address = "0x1234567890123456789012345678901234567890"
|
|
157
154
|
|
|
158
|
-
def
|
|
155
|
+
def best_quote_side_effect(*args, **kwargs):
|
|
159
156
|
to_token_address = kwargs.get("to_token_address", "")
|
|
160
157
|
if to_token_address == usdt0_address:
|
|
161
|
-
return (
|
|
162
|
-
True,
|
|
163
|
-
{
|
|
164
|
-
"quotes": {
|
|
165
|
-
"best_quote": {
|
|
166
|
-
"output_amount": "99900000",
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
)
|
|
158
|
+
return (True, {"output_amount": "99900000"})
|
|
171
159
|
return (
|
|
172
160
|
True,
|
|
173
161
|
{
|
|
174
|
-
"
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
"fromToken": {"symbol": "USDT0"},
|
|
182
|
-
"toToken": {"symbol": "HYPE"},
|
|
183
|
-
}
|
|
184
|
-
}
|
|
162
|
+
"output_amount": "105000000",
|
|
163
|
+
"input_amount": "50000000000000",
|
|
164
|
+
"toAmount": "105000000",
|
|
165
|
+
"estimatedGas": "1000000000",
|
|
166
|
+
"fromAmount": "100000000",
|
|
167
|
+
"fromToken": {"symbol": "USDT0"},
|
|
168
|
+
"toToken": {"symbol": "HYPE"},
|
|
185
169
|
},
|
|
186
170
|
)
|
|
187
171
|
|
|
188
|
-
s.brap_adapter.
|
|
189
|
-
side_effect=get_swap_quote_side_effect
|
|
190
|
-
)
|
|
172
|
+
s.brap_adapter.best_quote = AsyncMock(side_effect=best_quote_side_effect)
|
|
191
173
|
|
|
192
174
|
if (
|
|
193
175
|
hasattr(s, "brap_adapter")
|
|
194
176
|
and s.brap_adapter
|
|
195
177
|
and hasattr(s.brap_adapter, "swap_from_quote")
|
|
196
178
|
):
|
|
197
|
-
s.brap_adapter.swap_from_quote = AsyncMock(
|
|
179
|
+
s.brap_adapter.swap_from_quote = AsyncMock(
|
|
180
|
+
return_value=(
|
|
181
|
+
True,
|
|
182
|
+
{"tx_hash": "0xmockhash", "from_amount": "100", "to_amount": "99"},
|
|
183
|
+
)
|
|
184
|
+
)
|
|
198
185
|
|
|
199
186
|
if hasattr(s, "hyperlend_adapter") and s.hyperlend_adapter:
|
|
200
187
|
s.hyperlend_adapter.get_assets_view = AsyncMock(
|
|
@@ -13,7 +13,17 @@ from wayfinder_paths.adapters.brap_adapter.adapter import BRAPAdapter
|
|
|
13
13
|
from wayfinder_paths.adapters.ledger_adapter.adapter import LedgerAdapter
|
|
14
14
|
from wayfinder_paths.adapters.moonwell_adapter.adapter import MoonwellAdapter
|
|
15
15
|
from wayfinder_paths.adapters.token_adapter.adapter import TokenAdapter
|
|
16
|
+
from wayfinder_paths.core.constants.chains import CHAIN_ID_BASE
|
|
17
|
+
from wayfinder_paths.core.constants.contracts import BASE_USDC, BASE_WSTETH
|
|
16
18
|
from wayfinder_paths.core.constants.erc20_abi import ERC20_ABI
|
|
19
|
+
from wayfinder_paths.core.constants.tokens import (
|
|
20
|
+
TOKEN_ID_ETH_BASE,
|
|
21
|
+
TOKEN_ID_STETH,
|
|
22
|
+
TOKEN_ID_USDC_BASE,
|
|
23
|
+
TOKEN_ID_WELL_BASE,
|
|
24
|
+
TOKEN_ID_WETH_BASE,
|
|
25
|
+
TOKEN_ID_WSTETH_BASE,
|
|
26
|
+
)
|
|
17
27
|
from wayfinder_paths.core.strategies.descriptors import (
|
|
18
28
|
Complexity,
|
|
19
29
|
Directionality,
|
|
@@ -38,23 +48,17 @@ from wayfinder_paths.policies.moonwell import (
|
|
|
38
48
|
weth_deposit,
|
|
39
49
|
)
|
|
40
50
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
WSTETH = "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452"
|
|
44
|
-
|
|
45
|
-
# Token IDs
|
|
46
|
-
USDC_TOKEN_ID = "usd-coin-base"
|
|
47
|
-
WETH_TOKEN_ID = "l2-standard-bridged-weth-base-base"
|
|
48
|
-
WSTETH_TOKEN_ID = "superbridge-bridged-wsteth-base-base"
|
|
49
|
-
ETH_TOKEN_ID = "ethereum-base"
|
|
50
|
-
WELL_TOKEN_ID = "moonwell-artemis-base"
|
|
51
|
-
STETH_TOKEN_ID = "staked-ether-ethereum"
|
|
51
|
+
USDC = BASE_USDC
|
|
52
|
+
WSTETH = BASE_WSTETH
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
USDC_TOKEN_ID = TOKEN_ID_USDC_BASE
|
|
55
|
+
WETH_TOKEN_ID = TOKEN_ID_WETH_BASE
|
|
56
|
+
WSTETH_TOKEN_ID = TOKEN_ID_WSTETH_BASE
|
|
57
|
+
ETH_TOKEN_ID = TOKEN_ID_ETH_BASE
|
|
58
|
+
WELL_TOKEN_ID = TOKEN_ID_WELL_BASE
|
|
59
|
+
STETH_TOKEN_ID = TOKEN_ID_STETH
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
# 0.98 = 2% safety margin when borrowing to avoid hitting exact liquidation threshold
|
|
61
|
+
BASE_CHAIN_ID = CHAIN_ID_BASE
|
|
58
62
|
COLLATERAL_SAFETY_FACTOR = 0.98
|
|
59
63
|
|
|
60
64
|
|
|
@@ -3410,7 +3414,7 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
3410
3414
|
err: Exception | None = None
|
|
3411
3415
|
|
|
3412
3416
|
try:
|
|
3413
|
-
status = await self._withdraw_impl(
|
|
3417
|
+
status = await self._withdraw_impl()
|
|
3414
3418
|
except Exception as exc:
|
|
3415
3419
|
err = exc
|
|
3416
3420
|
if isinstance(exc, SwapOutcomeUnknownError):
|
|
@@ -3428,8 +3432,7 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
3428
3432
|
)
|
|
3429
3433
|
return (False, f"{status[1]} | {suffix}")
|
|
3430
3434
|
|
|
3431
|
-
async def _withdraw_impl(self
|
|
3432
|
-
# NOTE: amount is currently unused; withdraw() is all-or-nothing in this strategy.
|
|
3435
|
+
async def _withdraw_impl(self) -> StatusTuple:
|
|
3433
3436
|
logger.info("=" * 60)
|
|
3434
3437
|
logger.info("WITHDRAW START - Full position unwind")
|
|
3435
3438
|
logger.info("=" * 60)
|
|
@@ -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,
|
|
@@ -260,7 +259,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
260
259
|
for token_id in self.tracked_token_ids:
|
|
261
260
|
try:
|
|
262
261
|
success, balance_wei = await self.balance_adapter.get_balance(
|
|
263
|
-
|
|
262
|
+
token_id=token_id,
|
|
264
263
|
wallet_address=strategy_address,
|
|
265
264
|
)
|
|
266
265
|
if success and balance_wei:
|
|
@@ -373,11 +372,9 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
373
372
|
logger.info(f"Found {len(txns)} non-deposit transactions")
|
|
374
373
|
|
|
375
374
|
for txn in txns:
|
|
376
|
-
op_data = txn.get("
|
|
377
|
-
# Track any token that was swapped TO
|
|
375
|
+
op_data = txn.get("op_data", {})
|
|
378
376
|
if op_data.get("to_token_id"):
|
|
379
377
|
self._track_token(op_data.get("to_token_id"))
|
|
380
|
-
# Track any token that was swapped FROM
|
|
381
378
|
if op_data.get("from_token_id"):
|
|
382
379
|
self._track_token(op_data.get("from_token_id"))
|
|
383
380
|
|
|
@@ -392,29 +389,30 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
392
389
|
txns = []
|
|
393
390
|
|
|
394
391
|
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
|
-
|
|
392
|
+
last_txn = txns[-1]
|
|
393
|
+
pos = last_txn.get("op_data", {})
|
|
394
|
+
if pos and pos.get("to_token_id"):
|
|
395
|
+
success, token_info = await self.token_adapter.get_token(
|
|
396
|
+
pos.get("to_token_id")
|
|
397
|
+
)
|
|
398
|
+
if not success:
|
|
399
|
+
token_info = {}
|
|
400
|
+
self.current_pool = {
|
|
401
|
+
"token_id": token_info.get("token_id"),
|
|
402
|
+
"name": token_info.get("name"),
|
|
403
|
+
"symbol": token_info.get("symbol"),
|
|
404
|
+
"decimals": token_info.get("decimals"),
|
|
405
|
+
"address": token_info.get("address"),
|
|
406
|
+
"chain": token_info.get("chain"),
|
|
407
|
+
}
|
|
408
|
+
if token_info.get("token_id"):
|
|
409
|
+
self._track_token(token_info.get("token_id"))
|
|
412
410
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
411
|
+
success, reports = await self.pool_adapter.get_pools_by_ids(
|
|
412
|
+
pool_ids=[self.current_pool.get("token_id")]
|
|
413
|
+
)
|
|
414
|
+
if success and reports.get("pools"):
|
|
415
|
+
self.current_pool_data = reports.get("pools", [])[0]
|
|
418
416
|
|
|
419
417
|
pool_ids = []
|
|
420
418
|
pool_id = self.current_pool.get("token_id", None)
|
|
@@ -489,7 +487,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
489
487
|
success,
|
|
490
488
|
current_pool_balance_raw,
|
|
491
489
|
) = await self.balance_adapter.get_balance(
|
|
492
|
-
|
|
490
|
+
token_address=pool_address,
|
|
493
491
|
wallet_address=user_address,
|
|
494
492
|
chain_id=chain_id,
|
|
495
493
|
)
|
|
@@ -537,7 +535,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
537
535
|
|
|
538
536
|
if self.usdc_token_info:
|
|
539
537
|
status, raw_balance = await self.balance_adapter.get_balance(
|
|
540
|
-
|
|
538
|
+
token_id=self.usdc_token_info.get("token_id"),
|
|
541
539
|
wallet_address=self._get_strategy_wallet_address(),
|
|
542
540
|
)
|
|
543
541
|
if not status or not raw_balance:
|
|
@@ -608,7 +606,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
608
606
|
strategy_address = self._get_strategy_wallet_address()
|
|
609
607
|
try:
|
|
610
608
|
success, onchain_balance = await self.balance_adapter.get_balance(
|
|
611
|
-
|
|
609
|
+
token_id=token.get("token_id"),
|
|
612
610
|
wallet_address=strategy_address,
|
|
613
611
|
)
|
|
614
612
|
if success and onchain_balance:
|
|
@@ -686,7 +684,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
686
684
|
main_usdc_status,
|
|
687
685
|
main_usdc_balance,
|
|
688
686
|
) = await self.balance_adapter.get_balance(
|
|
689
|
-
|
|
687
|
+
token_id=token_info.get("token_id"),
|
|
690
688
|
wallet_address=self._get_main_wallet_address(),
|
|
691
689
|
)
|
|
692
690
|
if main_usdc_status and main_usdc_balance is not None:
|
|
@@ -730,7 +728,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
730
728
|
_,
|
|
731
729
|
main_gas_raw,
|
|
732
730
|
) = await self.balance_adapter.get_balance(
|
|
733
|
-
|
|
731
|
+
token_id=gas_token_id,
|
|
734
732
|
wallet_address=self._get_main_wallet_address(),
|
|
735
733
|
)
|
|
736
734
|
main_gas_int = (
|
|
@@ -754,14 +752,14 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
754
752
|
_,
|
|
755
753
|
main_gas_raw,
|
|
756
754
|
) = await self.balance_adapter.get_balance(
|
|
757
|
-
|
|
755
|
+
token_id=gas_token_id,
|
|
758
756
|
wallet_address=self._get_main_wallet_address(),
|
|
759
757
|
)
|
|
760
758
|
(
|
|
761
759
|
_,
|
|
762
760
|
strategy_gas_raw,
|
|
763
761
|
) = await self.balance_adapter.get_balance(
|
|
764
|
-
|
|
762
|
+
token_id=gas_token_id,
|
|
765
763
|
wallet_address=self._get_strategy_wallet_address(),
|
|
766
764
|
)
|
|
767
765
|
main_gas_int = (
|
|
@@ -885,7 +883,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
885
883
|
_,
|
|
886
884
|
self.current_pool_balance,
|
|
887
885
|
) = await self.balance_adapter.get_balance(
|
|
888
|
-
|
|
886
|
+
token_address=self.current_pool.get("address"),
|
|
889
887
|
wallet_address=self._get_strategy_wallet_address(),
|
|
890
888
|
chain_id=self.current_pool.get("chain").get("id"),
|
|
891
889
|
)
|
|
@@ -901,76 +899,26 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
901
899
|
logger.info(
|
|
902
900
|
f"Need to swap from {self.current_pool.get('symbol')} to USDC before withdrawal"
|
|
903
901
|
)
|
|
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:
|
|
902
|
+
success, quote = await self.brap_adapter.best_quote(
|
|
903
|
+
from_token_address=self.current_pool.get("address"),
|
|
904
|
+
to_token_address=self.usdc_token_info.get("address"),
|
|
905
|
+
from_chain_id=self.current_pool.get("chain").get("id"),
|
|
906
|
+
to_chain_id=self.usdc_token_info.get("chain").get("id"),
|
|
907
|
+
from_address=self._get_strategy_wallet_address(),
|
|
908
|
+
amount=str(self.current_pool_balance),
|
|
909
|
+
retries=4,
|
|
910
|
+
)
|
|
911
|
+
if not success:
|
|
934
912
|
return (
|
|
935
913
|
False,
|
|
936
914
|
"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
915
|
)
|
|
938
916
|
|
|
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
917
|
success, swap_result = await self.brap_adapter.swap_from_quote(
|
|
970
918
|
self.current_pool,
|
|
971
919
|
self.usdc_token_info,
|
|
972
920
|
self._get_strategy_wallet_address(),
|
|
973
|
-
|
|
921
|
+
quote,
|
|
974
922
|
strategy_name=self.name,
|
|
975
923
|
)
|
|
976
924
|
if not success:
|
|
@@ -982,7 +930,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
982
930
|
await self._sweep_wallet(self.usdc_token_info)
|
|
983
931
|
|
|
984
932
|
status, raw_balance = await self.balance_adapter.get_balance(
|
|
985
|
-
|
|
933
|
+
token_id=self.usdc_token_info.get("token_id"),
|
|
986
934
|
wallet_address=self._get_strategy_wallet_address(),
|
|
987
935
|
)
|
|
988
936
|
usdc_amount = 0.0
|
|
@@ -994,7 +942,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
994
942
|
gas_amount = 0.0
|
|
995
943
|
if self.gas_token:
|
|
996
944
|
status, raw_gas = await self.balance_adapter.get_balance(
|
|
997
|
-
|
|
945
|
+
token_id=self.gas_token.get("token_id"),
|
|
998
946
|
wallet_address=self._get_strategy_wallet_address(),
|
|
999
947
|
)
|
|
1000
948
|
if status and raw_gas:
|
|
@@ -1043,7 +991,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1043
991
|
success,
|
|
1044
992
|
msg,
|
|
1045
993
|
) = await self.balance_adapter.move_from_strategy_wallet_to_main_wallet(
|
|
1046
|
-
|
|
994
|
+
token_id="usd-coin-base",
|
|
1047
995
|
amount=usdc_balance,
|
|
1048
996
|
strategy_name=self.name,
|
|
1049
997
|
skip_ledger=False,
|
|
@@ -1068,7 +1016,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1068
1016
|
success,
|
|
1069
1017
|
msg,
|
|
1070
1018
|
) = await self.balance_adapter.move_from_strategy_wallet_to_main_wallet(
|
|
1071
|
-
|
|
1019
|
+
token_id="ethereum-base",
|
|
1072
1020
|
amount=transferable_eth,
|
|
1073
1021
|
strategy_name=self.name,
|
|
1074
1022
|
skip_ledger=False,
|
|
@@ -1091,12 +1039,16 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1091
1039
|
return None
|
|
1092
1040
|
for transaction in data.get("transactions", []):
|
|
1093
1041
|
op_data = transaction.get("op_data", {})
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1042
|
+
to_token = op_data.get("to_token_id")
|
|
1043
|
+
if (
|
|
1044
|
+
op_data.get("type") == "SWAP"
|
|
1045
|
+
and to_token
|
|
1046
|
+
and str(to_token).lower()
|
|
1047
|
+
not in [
|
|
1048
|
+
"usd-coin-base",
|
|
1049
|
+
"base_0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
1050
|
+
]
|
|
1051
|
+
):
|
|
1100
1052
|
created_str = transaction.get("created")
|
|
1101
1053
|
if not created_str:
|
|
1102
1054
|
continue
|
|
@@ -1262,7 +1214,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1262
1214
|
_,
|
|
1263
1215
|
refreshed_pool_balance,
|
|
1264
1216
|
) = await self.balance_adapter.get_balance(
|
|
1265
|
-
|
|
1217
|
+
token_address=pool.get("address"),
|
|
1266
1218
|
wallet_address=strategy_address,
|
|
1267
1219
|
chain_id=pool.get("chain").get("id"),
|
|
1268
1220
|
)
|
|
@@ -1295,7 +1247,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1295
1247
|
|
|
1296
1248
|
try:
|
|
1297
1249
|
success, fresh_balance = await self.balance_adapter.get_balance(
|
|
1298
|
-
|
|
1250
|
+
token_id=token_id,
|
|
1299
1251
|
wallet_address=self._get_strategy_wallet_address(),
|
|
1300
1252
|
)
|
|
1301
1253
|
if not success or not fresh_balance or int(fresh_balance) <= 0:
|
|
@@ -1334,7 +1286,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1334
1286
|
# Refresh target token balance
|
|
1335
1287
|
try:
|
|
1336
1288
|
success, target_balance = await self.balance_adapter.get_balance(
|
|
1337
|
-
|
|
1289
|
+
token_id=target_token_id,
|
|
1338
1290
|
wallet_address=self._get_strategy_wallet_address(),
|
|
1339
1291
|
)
|
|
1340
1292
|
if success and target_balance:
|
|
@@ -1351,7 +1303,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1351
1303
|
|
|
1352
1304
|
required_gas = int(self.MIN_GAS * (10 ** self.gas_token.get("decimals")))
|
|
1353
1305
|
_, current_gas = await self.balance_adapter.get_balance(
|
|
1354
|
-
|
|
1306
|
+
token_id=self.gas_token.get("token_id"),
|
|
1355
1307
|
wallet_address=strategy_address,
|
|
1356
1308
|
)
|
|
1357
1309
|
if current_gas >= required_gas:
|
|
@@ -1399,22 +1351,15 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1399
1351
|
if chain_id != self.usdc_token_info.get("chain").get("id"):
|
|
1400
1352
|
return 0.0
|
|
1401
1353
|
|
|
1402
|
-
success,
|
|
1354
|
+
success, best_quote = await self.brap_adapter.best_quote(
|
|
1403
1355
|
from_token_address=token.get("address"),
|
|
1404
1356
|
to_token_address=self.usdc_token_info.get("address"),
|
|
1405
1357
|
from_chain_id=chain_id,
|
|
1406
1358
|
to_chain_id=self.usdc_token_info.get("chain").get("id"),
|
|
1407
1359
|
from_address=self._get_strategy_wallet_address(),
|
|
1408
|
-
to_address=self._get_strategy_wallet_address(),
|
|
1409
1360
|
amount=str(amount),
|
|
1410
1361
|
)
|
|
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:
|
|
1362
|
+
if not success or not isinstance(best_quote, dict):
|
|
1418
1363
|
return None
|
|
1419
1364
|
current_pool_usd_value = best_quote.get("output_amount")
|
|
1420
1365
|
|
|
@@ -1538,21 +1483,15 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1538
1483
|
try:
|
|
1539
1484
|
apy_pct = pool_data.get("combined_apy_pct") or pool_data.get("apy") or 0
|
|
1540
1485
|
combined_apy_pct = float(apy_pct) / 100
|
|
1541
|
-
success,
|
|
1486
|
+
success, best_quote = await self.brap_adapter.best_quote(
|
|
1542
1487
|
from_token_address=current_token.get("address"),
|
|
1543
1488
|
to_token_address=token.get("address"),
|
|
1544
1489
|
from_chain_id=current_token.get("chain").get("id"),
|
|
1545
1490
|
to_chain_id=token.get("chain").get("id"),
|
|
1546
1491
|
from_address=self._get_strategy_wallet_address(),
|
|
1547
|
-
to_address=self._get_strategy_wallet_address(),
|
|
1548
1492
|
amount=str(current_token_balance),
|
|
1549
1493
|
)
|
|
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:
|
|
1494
|
+
if not success or not isinstance(best_quote, dict):
|
|
1556
1495
|
return None
|
|
1557
1496
|
|
|
1558
1497
|
target_pool_usd_val = await self._get_pool_usd_value(
|
|
@@ -1602,7 +1541,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1602
1541
|
|
|
1603
1542
|
async def _status(self) -> StatusDict:
|
|
1604
1543
|
gas_success, gas_balance_wei = await self.balance_adapter.get_balance(
|
|
1605
|
-
|
|
1544
|
+
token_id=self.gas_token.get("token_id"),
|
|
1606
1545
|
wallet_address=self._get_strategy_wallet_address(),
|
|
1607
1546
|
)
|
|
1608
1547
|
gas_balance = (
|
|
@@ -1759,7 +1698,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1759
1698
|
|
|
1760
1699
|
# Refresh USDC balance after swaps
|
|
1761
1700
|
success, usdc_wei = await self.balance_adapter.get_balance(
|
|
1762
|
-
|
|
1701
|
+
token_id=usdc_token_id,
|
|
1763
1702
|
wallet_address=self._get_strategy_wallet_address(),
|
|
1764
1703
|
)
|
|
1765
1704
|
if success and usdc_wei:
|
|
@@ -1804,7 +1743,7 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1804
1743
|
|
|
1805
1744
|
# Refresh USDC balance again
|
|
1806
1745
|
success, usdc_wei = await self.balance_adapter.get_balance(
|
|
1807
|
-
|
|
1746
|
+
token_id=usdc_token_id,
|
|
1808
1747
|
wallet_address=self._get_strategy_wallet_address(),
|
|
1809
1748
|
)
|
|
1810
1749
|
if success and usdc_wei:
|