wayfinder-paths 0.1.15__py3-none-any.whl → 0.1.16__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/adapters/balance_adapter/README.md +19 -20
- wayfinder_paths/adapters/balance_adapter/adapter.py +66 -37
- wayfinder_paths/adapters/balance_adapter/test_adapter.py +2 -8
- wayfinder_paths/adapters/brap_adapter/README.md +22 -19
- wayfinder_paths/adapters/brap_adapter/adapter.py +33 -34
- wayfinder_paths/adapters/brap_adapter/test_adapter.py +2 -18
- wayfinder_paths/adapters/hyperlend_adapter/adapter.py +40 -56
- wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +1 -8
- wayfinder_paths/adapters/moonwell_adapter/README.md +29 -31
- wayfinder_paths/adapters/moonwell_adapter/adapter.py +301 -662
- wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +275 -179
- wayfinder_paths/core/config.py +8 -47
- wayfinder_paths/core/constants/base.py +0 -1
- wayfinder_paths/core/constants/erc20_abi.py +13 -13
- wayfinder_paths/core/strategies/Strategy.py +6 -2
- wayfinder_paths/core/utils/erc20_service.py +100 -0
- wayfinder_paths/core/utils/evm_helpers.py +1 -1
- wayfinder_paths/core/utils/transaction.py +191 -0
- wayfinder_paths/core/utils/web3.py +66 -0
- wayfinder_paths/run_strategy.py +37 -6
- wayfinder_paths/strategies/basis_trading_strategy/strategy.py +200 -224
- wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +128 -151
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +0 -1
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +52 -78
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +0 -12
- wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/README.md +0 -1
- wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +39 -64
- wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +0 -1
- wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +42 -85
- wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +0 -8
- wayfinder_paths/templates/strategy/README.md +1 -5
- {wayfinder_paths-0.1.15.dist-info → wayfinder_paths-0.1.16.dist-info}/METADATA +3 -41
- {wayfinder_paths-0.1.15.dist-info → wayfinder_paths-0.1.16.dist-info}/RECORD +35 -44
- {wayfinder_paths-0.1.15.dist-info → wayfinder_paths-0.1.16.dist-info}/WHEEL +1 -1
- wayfinder_paths/core/clients/sdk_example.py +0 -125
- wayfinder_paths/core/engine/__init__.py +0 -5
- wayfinder_paths/core/services/__init__.py +0 -0
- wayfinder_paths/core/services/base.py +0 -131
- wayfinder_paths/core/services/local_evm_txn.py +0 -350
- wayfinder_paths/core/services/local_token_txn.py +0 -238
- wayfinder_paths/core/services/web3_service.py +0 -43
- wayfinder_paths/core/wallets/README.md +0 -88
- wayfinder_paths/core/wallets/WalletManager.py +0 -56
- wayfinder_paths/core/wallets/__init__.py +0 -7
- wayfinder_paths/scripts/run_strategy.py +0 -152
- wayfinder_paths/strategies/config.py +0 -85
- {wayfinder_paths-0.1.15.dist-info → wayfinder_paths-0.1.16.dist-info}/LICENSE +0 -0
|
@@ -8,6 +8,7 @@ so the position remains safe under a stETH/ETH depeg.
|
|
|
8
8
|
|
|
9
9
|
import asyncio
|
|
10
10
|
import time
|
|
11
|
+
from collections.abc import Awaitable, Callable
|
|
11
12
|
from dataclasses import dataclass
|
|
12
13
|
from typing import Any, Optional
|
|
13
14
|
|
|
@@ -21,9 +22,6 @@ from wayfinder_paths.adapters.ledger_adapter.adapter import LedgerAdapter
|
|
|
21
22
|
from wayfinder_paths.adapters.moonwell_adapter.adapter import MoonwellAdapter
|
|
22
23
|
from wayfinder_paths.adapters.token_adapter.adapter import TokenAdapter
|
|
23
24
|
from wayfinder_paths.core.constants.erc20_abi import ERC20_ABI
|
|
24
|
-
from wayfinder_paths.core.services.base import Web3Service
|
|
25
|
-
from wayfinder_paths.core.services.local_token_txn import LocalTokenTxnService
|
|
26
|
-
from wayfinder_paths.core.services.web3_service import DefaultWeb3Service
|
|
27
25
|
from wayfinder_paths.core.strategies.descriptors import (
|
|
28
26
|
Complexity,
|
|
29
27
|
Directionality,
|
|
@@ -33,7 +31,7 @@ from wayfinder_paths.core.strategies.descriptors import (
|
|
|
33
31
|
Volatility,
|
|
34
32
|
)
|
|
35
33
|
from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
|
|
36
|
-
from wayfinder_paths.core.
|
|
34
|
+
from wayfinder_paths.core.utils.web3 import web3_from_chain_id
|
|
37
35
|
from wayfinder_paths.policies.enso import ENSO_ROUTER, enso_swap
|
|
38
36
|
from wayfinder_paths.policies.erc20 import erc20_spender_for_any_token
|
|
39
37
|
from wayfinder_paths.policies.moonwell import (
|
|
@@ -191,9 +189,16 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
191
189
|
main_wallet: dict | None = None,
|
|
192
190
|
strategy_wallet: dict | None = None,
|
|
193
191
|
simulation: bool = False,
|
|
194
|
-
|
|
192
|
+
api_key: str | None = None,
|
|
193
|
+
main_wallet_signing_callback: Callable[[dict], Awaitable[str]] | None = None,
|
|
194
|
+
strategy_wallet_signing_callback: Callable[[dict], Awaitable[str]]
|
|
195
|
+
| None = None,
|
|
195
196
|
):
|
|
196
|
-
super().__init__(
|
|
197
|
+
super().__init__(
|
|
198
|
+
api_key=api_key,
|
|
199
|
+
main_wallet_signing_callback=main_wallet_signing_callback,
|
|
200
|
+
strategy_wallet_signing_callback=strategy_wallet_signing_callback,
|
|
201
|
+
)
|
|
197
202
|
merged_config: dict[str, Any] = dict(config or {})
|
|
198
203
|
if main_wallet is not None:
|
|
199
204
|
merged_config["main_wallet"] = main_wallet
|
|
@@ -202,7 +207,6 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
202
207
|
|
|
203
208
|
self.config = merged_config
|
|
204
209
|
self.simulation = simulation
|
|
205
|
-
self.web3_service = web3_service
|
|
206
210
|
|
|
207
211
|
# Adapter references
|
|
208
212
|
self.balance_adapter: BalanceAdapter | None = None
|
|
@@ -231,32 +235,24 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
231
235
|
"strategy": self.config,
|
|
232
236
|
}
|
|
233
237
|
|
|
234
|
-
# Initialize web3_service if not provided
|
|
235
|
-
if self.web3_service is None:
|
|
236
|
-
wallet_provider = WalletManager.get_provider(adapter_config)
|
|
237
|
-
token_transaction_service = LocalTokenTxnService(
|
|
238
|
-
adapter_config,
|
|
239
|
-
wallet_provider=wallet_provider,
|
|
240
|
-
)
|
|
241
|
-
web3_service = DefaultWeb3Service(
|
|
242
|
-
wallet_provider=wallet_provider,
|
|
243
|
-
evm_transactions=token_transaction_service,
|
|
244
|
-
)
|
|
245
|
-
else:
|
|
246
|
-
web3_service = self.web3_service
|
|
247
|
-
token_transaction_service = web3_service.token_transactions
|
|
248
|
-
|
|
249
238
|
# Initialize adapters
|
|
250
|
-
balance = BalanceAdapter(
|
|
239
|
+
balance = BalanceAdapter(
|
|
240
|
+
adapter_config,
|
|
241
|
+
simulation=self.simulation,
|
|
242
|
+
main_wallet_signing_callback=self.main_wallet_signing_callback,
|
|
243
|
+
strategy_wallet_signing_callback=self.strategy_wallet_signing_callback,
|
|
244
|
+
)
|
|
251
245
|
token_adapter = TokenAdapter()
|
|
252
246
|
ledger_adapter = LedgerAdapter()
|
|
253
247
|
brap_adapter = BRAPAdapter(
|
|
254
|
-
|
|
248
|
+
adapter_config,
|
|
249
|
+
simulation=self.simulation,
|
|
250
|
+
strategy_wallet_signing_callback=self.strategy_wallet_signing_callback,
|
|
255
251
|
)
|
|
256
252
|
moonwell_adapter = MoonwellAdapter(
|
|
257
253
|
adapter_config,
|
|
258
254
|
simulation=self.simulation,
|
|
259
|
-
|
|
255
|
+
strategy_wallet_signing_callback=self.strategy_wallet_signing_callback,
|
|
260
256
|
)
|
|
261
257
|
|
|
262
258
|
self.register_adapters(
|
|
@@ -266,7 +262,6 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
266
262
|
ledger_adapter,
|
|
267
263
|
brap_adapter,
|
|
268
264
|
moonwell_adapter,
|
|
269
|
-
token_transaction_service,
|
|
270
265
|
]
|
|
271
266
|
)
|
|
272
267
|
|
|
@@ -275,7 +270,6 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
275
270
|
self.ledger_adapter = ledger_adapter
|
|
276
271
|
self.brap_adapter = brap_adapter
|
|
277
272
|
self.moonwell_adapter = moonwell_adapter
|
|
278
|
-
self.web3_service = web3_service
|
|
279
273
|
|
|
280
274
|
except Exception as e:
|
|
281
275
|
logger.error(f"Failed to initialize strategy adapters: {e}")
|
|
@@ -1893,7 +1887,7 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
1893
1887
|
return 0
|
|
1894
1888
|
|
|
1895
1889
|
# Tests/simulations patch adapters; avoid RPC calls there.
|
|
1896
|
-
if self.simulation
|
|
1890
|
+
if self.simulation:
|
|
1897
1891
|
if self.balance_adapter is None:
|
|
1898
1892
|
return 0
|
|
1899
1893
|
success, raw = await self.balance_adapter.get_balance(
|
|
@@ -1927,25 +1921,23 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
1927
1921
|
last_error: Exception | None = None
|
|
1928
1922
|
|
|
1929
1923
|
for attempt in range(max_retries):
|
|
1930
|
-
w3 = None
|
|
1931
1924
|
try:
|
|
1932
|
-
|
|
1925
|
+
async with web3_from_chain_id(BASE_CHAIN_ID) as w3:
|
|
1926
|
+
if token_id == ETH_TOKEN_ID:
|
|
1927
|
+
bal = await w3.eth.get_balance(
|
|
1928
|
+
to_checksum_address(wallet_address),
|
|
1929
|
+
block_identifier=block_id,
|
|
1930
|
+
)
|
|
1931
|
+
return int(bal)
|
|
1933
1932
|
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
block_identifier=block_id,
|
|
1933
|
+
contract = w3.eth.contract(
|
|
1934
|
+
address=to_checksum_address(str(token_address)),
|
|
1935
|
+
abi=ERC20_ABI,
|
|
1938
1936
|
)
|
|
1937
|
+
bal = await contract.functions.balanceOf(
|
|
1938
|
+
to_checksum_address(wallet_address)
|
|
1939
|
+
).call(block_identifier=block_id)
|
|
1939
1940
|
return int(bal)
|
|
1940
|
-
|
|
1941
|
-
contract = w3.eth.contract(
|
|
1942
|
-
address=to_checksum_address(str(token_address)),
|
|
1943
|
-
abi=ERC20_ABI,
|
|
1944
|
-
)
|
|
1945
|
-
bal = await contract.functions.balanceOf(
|
|
1946
|
-
to_checksum_address(wallet_address)
|
|
1947
|
-
).call(block_identifier=block_id)
|
|
1948
|
-
return int(bal)
|
|
1949
1941
|
except Exception as exc:
|
|
1950
1942
|
last_error = exc if isinstance(exc, Exception) else Exception(str(exc))
|
|
1951
1943
|
err = str(exc)
|
|
@@ -1959,16 +1951,6 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
1959
1951
|
f"On-chain balance read failed for {token_id} at block {block_id}: {exc}"
|
|
1960
1952
|
)
|
|
1961
1953
|
return 0
|
|
1962
|
-
finally:
|
|
1963
|
-
if w3 is not None:
|
|
1964
|
-
try:
|
|
1965
|
-
close_web3 = getattr(
|
|
1966
|
-
self.web3_service.evm_transactions, "_close_web3", None
|
|
1967
|
-
)
|
|
1968
|
-
if close_web3 is not None:
|
|
1969
|
-
await close_web3(w3)
|
|
1970
|
-
except Exception:
|
|
1971
|
-
pass
|
|
1972
1954
|
|
|
1973
1955
|
logger.warning(
|
|
1974
1956
|
f"On-chain balance read failed after {max_retries} attempts for {token_id} "
|
|
@@ -3231,22 +3213,15 @@ class MoonwellWstethLoopStrategy(Strategy):
|
|
|
3231
3213
|
logger.info("UPDATE START")
|
|
3232
3214
|
logger.info("=" * 60)
|
|
3233
3215
|
|
|
3234
|
-
#
|
|
3235
|
-
topup_success, topup_msg = await self._transfer_gas_to_vault()
|
|
3236
|
-
if not topup_success:
|
|
3237
|
-
logger.warning(f"Gas top-up failed (non-critical): {topup_msg}")
|
|
3238
|
-
|
|
3216
|
+
# Check gas balance - deposit() should have provided sufficient gas
|
|
3239
3217
|
gas_amt = await self._get_gas_balance()
|
|
3240
3218
|
logger.info(
|
|
3241
3219
|
f"Gas balance: {gas_amt / 10**18:.6f} ETH (min: {self.MAINTENANCE_GAS} ETH)"
|
|
3242
3220
|
)
|
|
3243
3221
|
if gas_amt < int(self.MAINTENANCE_GAS * 10**18):
|
|
3244
|
-
logger.
|
|
3245
|
-
f"
|
|
3246
|
-
|
|
3247
|
-
return (
|
|
3248
|
-
False,
|
|
3249
|
-
f"Less than {self.MAINTENANCE_GAS} ETH in strategy wallet. Please transfer more gas.",
|
|
3222
|
+
logger.warning(
|
|
3223
|
+
f"Low gas: {gas_amt / 10**18:.6f} < {self.MAINTENANCE_GAS} ETH. "
|
|
3224
|
+
f"Transactions may fail. Call deposit() with gas to top up."
|
|
3250
3225
|
)
|
|
3251
3226
|
|
|
3252
3227
|
# Pre-fetch collateral factors once (saves RPC + makes decisions consistent)
|
|
@@ -32,7 +32,6 @@ Transactions are scoped to the strategy wallet and Enso Router approval/swap cal
|
|
|
32
32
|
- `BRAPAdapter` to source swap quotes and execute rotations.
|
|
33
33
|
- `TokenAdapter` for metadata (gas token, USDC info).
|
|
34
34
|
- `LedgerAdapter` for net-deposit tracking and cooldown enforcement.
|
|
35
|
-
- `LocalTokenTxnService` (via `DefaultWeb3Service`) for lower-level sends/approvals used by adapters.
|
|
36
35
|
|
|
37
36
|
## Actions
|
|
38
37
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import math
|
|
3
3
|
import time
|
|
4
|
+
from collections.abc import Awaitable, Callable
|
|
4
5
|
from datetime import UTC, datetime, timedelta
|
|
5
6
|
from typing import Any
|
|
6
7
|
|
|
@@ -12,10 +13,6 @@ from wayfinder_paths.adapters.ledger_adapter.adapter import LedgerAdapter
|
|
|
12
13
|
from wayfinder_paths.adapters.pool_adapter.adapter import PoolAdapter
|
|
13
14
|
from wayfinder_paths.adapters.token_adapter.adapter import TokenAdapter
|
|
14
15
|
from wayfinder_paths.core.constants.base import DEFAULT_SLIPPAGE
|
|
15
|
-
from wayfinder_paths.core.services.local_token_txn import (
|
|
16
|
-
LocalTokenTxnService,
|
|
17
|
-
)
|
|
18
|
-
from wayfinder_paths.core.services.web3_service import DefaultWeb3Service
|
|
19
16
|
from wayfinder_paths.core.strategies.descriptors import (
|
|
20
17
|
Complexity,
|
|
21
18
|
Directionality,
|
|
@@ -25,7 +22,6 @@ from wayfinder_paths.core.strategies.descriptors import (
|
|
|
25
22
|
Volatility,
|
|
26
23
|
)
|
|
27
24
|
from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
|
|
28
|
-
from wayfinder_paths.core.wallets.WalletManager import WalletManager
|
|
29
25
|
|
|
30
26
|
|
|
31
27
|
class StablecoinYieldStrategy(Strategy):
|
|
@@ -156,9 +152,16 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
156
152
|
*,
|
|
157
153
|
main_wallet: dict[str, Any] | None = None,
|
|
158
154
|
strategy_wallet: dict[str, Any] | None = None,
|
|
159
|
-
|
|
155
|
+
api_key: str | None = None,
|
|
156
|
+
main_wallet_signing_callback: Callable[[dict], Awaitable[str]] | None = None,
|
|
157
|
+
strategy_wallet_signing_callback: Callable[[dict], Awaitable[str]]
|
|
158
|
+
| None = None,
|
|
160
159
|
):
|
|
161
|
-
super().__init__(
|
|
160
|
+
super().__init__(
|
|
161
|
+
api_key=api_key,
|
|
162
|
+
main_wallet_signing_callback=main_wallet_signing_callback,
|
|
163
|
+
strategy_wallet_signing_callback=strategy_wallet_signing_callback,
|
|
164
|
+
)
|
|
162
165
|
merged_config: dict[str, Any] = dict(config or {})
|
|
163
166
|
if main_wallet is not None:
|
|
164
167
|
merged_config["main_wallet"] = main_wallet
|
|
@@ -170,16 +173,16 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
170
173
|
self.current_pool = None
|
|
171
174
|
self.current_apy = 0
|
|
172
175
|
self.balance_adapter = None
|
|
173
|
-
self.tx_adapter = None
|
|
174
|
-
self.web3_service = web3_service
|
|
175
176
|
self.token_adapter = None
|
|
176
177
|
self.ledger_adapter = None
|
|
177
178
|
self.pool_adapter = None
|
|
178
179
|
self.brap_adapter = None
|
|
179
180
|
|
|
180
181
|
# State tracking for deterministic token management
|
|
181
|
-
|
|
182
|
-
self.
|
|
182
|
+
# All tokens strategy might hold
|
|
183
|
+
self.tracked_token_ids: set[str] = set()
|
|
184
|
+
# token_id -> balance in wei
|
|
185
|
+
self.tracked_balances: dict[str, int] = {}
|
|
183
186
|
|
|
184
187
|
try:
|
|
185
188
|
main_wallet_cfg = self.config.get("main_wallet")
|
|
@@ -191,23 +194,18 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
191
194
|
"strategy": self.config,
|
|
192
195
|
}
|
|
193
196
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
)
|
|
200
|
-
web3_service = DefaultWeb3Service(
|
|
201
|
-
wallet_provider=wallet_provider, evm_transactions=tx_adapter
|
|
202
|
-
)
|
|
203
|
-
else:
|
|
204
|
-
web3_service = self.web3_service
|
|
205
|
-
tx_adapter = web3_service.token_transactions
|
|
206
|
-
balance = BalanceAdapter(adapter_config, web3_service=web3_service)
|
|
197
|
+
balance = BalanceAdapter(
|
|
198
|
+
adapter_config,
|
|
199
|
+
main_wallet_signing_callback=self.main_wallet_signing_callback,
|
|
200
|
+
strategy_wallet_signing_callback=self.strategy_wallet_signing_callback,
|
|
201
|
+
)
|
|
207
202
|
token_adapter = TokenAdapter()
|
|
208
203
|
ledger_adapter = LedgerAdapter()
|
|
209
204
|
pool_adapter = PoolAdapter()
|
|
210
|
-
brap_adapter = BRAPAdapter(
|
|
205
|
+
brap_adapter = BRAPAdapter(
|
|
206
|
+
adapter_config,
|
|
207
|
+
strategy_wallet_signing_callback=self.strategy_wallet_signing_callback,
|
|
208
|
+
)
|
|
211
209
|
|
|
212
210
|
self.register_adapters(
|
|
213
211
|
[
|
|
@@ -216,12 +214,9 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
216
214
|
ledger_adapter,
|
|
217
215
|
pool_adapter,
|
|
218
216
|
brap_adapter,
|
|
219
|
-
tx_adapter,
|
|
220
217
|
]
|
|
221
218
|
)
|
|
222
219
|
self.balance_adapter = balance
|
|
223
|
-
self.tx_adapter = tx_adapter
|
|
224
|
-
self.web3_service = web3_service
|
|
225
220
|
self.token_adapter = token_adapter
|
|
226
221
|
self.ledger_adapter = ledger_adapter
|
|
227
222
|
self.pool_adapter = pool_adapter
|
|
@@ -1010,83 +1005,45 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
1010
1005
|
)
|
|
1011
1006
|
|
|
1012
1007
|
await self._sweep_wallet(self.usdc_token_info)
|
|
1013
|
-
withdrawn_breakdown = []
|
|
1014
|
-
withdrawn_token_ids = set()
|
|
1015
1008
|
|
|
1016
|
-
|
|
1017
|
-
pass
|
|
1009
|
+
# Get final USDC balance in strategy wallet
|
|
1018
1010
|
status, raw_balance = await self.balance_adapter.get_balance(
|
|
1019
1011
|
query=self.usdc_token_info.get("token_id"),
|
|
1020
1012
|
wallet_address=self._get_strategy_wallet_address(),
|
|
1021
1013
|
)
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
(
|
|
1027
|
-
move_status,
|
|
1028
|
-
move_message,
|
|
1029
|
-
) = await self.balance_adapter.move_from_strategy_wallet_to_main_wallet(
|
|
1030
|
-
self.usdc_token_info.get("token_id"),
|
|
1031
|
-
amount,
|
|
1032
|
-
strategy_name=self.name,
|
|
1033
|
-
)
|
|
1034
|
-
if not move_status:
|
|
1035
|
-
return (False, f"USDC return to main failed: {move_message}")
|
|
1036
|
-
|
|
1037
|
-
withdrawn_breakdown.append(
|
|
1038
|
-
(
|
|
1039
|
-
self.usdc_token_info.get("symbol"),
|
|
1040
|
-
self.usdc_token_info.get("chain").get("name"),
|
|
1041
|
-
float(amount),
|
|
1014
|
+
usdc_amount = 0.0
|
|
1015
|
+
if status and raw_balance:
|
|
1016
|
+
usdc_amount = float(raw_balance) / 10 ** self.usdc_token_info.get(
|
|
1017
|
+
"decimals"
|
|
1042
1018
|
)
|
|
1043
|
-
)
|
|
1044
|
-
withdrawn_token_ids.add(self.usdc_token_info.get("token_id"))
|
|
1045
1019
|
|
|
1046
|
-
|
|
1020
|
+
# Get gas balance in strategy wallet
|
|
1021
|
+
gas_amount = 0.0
|
|
1022
|
+
if self.gas_token:
|
|
1047
1023
|
status, raw_gas = await self.balance_adapter.get_balance(
|
|
1048
1024
|
query=self.gas_token.get("token_id"),
|
|
1049
1025
|
wallet_address=self._get_strategy_wallet_address(),
|
|
1050
1026
|
)
|
|
1051
1027
|
if status and raw_gas:
|
|
1052
|
-
gas_amount = (
|
|
1053
|
-
float(raw_gas) / 10 ** self.gas_token.get("decimals")
|
|
1054
|
-
) * 0.9
|
|
1055
|
-
if gas_amount > 0:
|
|
1056
|
-
(
|
|
1057
|
-
move_gas_status,
|
|
1058
|
-
move_gas_message,
|
|
1059
|
-
) = await self.balance_adapter.move_from_strategy_wallet_to_main_wallet(
|
|
1060
|
-
self.gas_token.get("token_id"),
|
|
1061
|
-
gas_amount,
|
|
1062
|
-
strategy_name=self.name,
|
|
1063
|
-
)
|
|
1064
|
-
if move_gas_status:
|
|
1065
|
-
withdrawn_breakdown.append(
|
|
1066
|
-
(
|
|
1067
|
-
self.gas_token.get("symbol"),
|
|
1068
|
-
self.gas_token.get("chain").get("name"),
|
|
1069
|
-
float(gas_amount),
|
|
1070
|
-
)
|
|
1071
|
-
)
|
|
1072
|
-
withdrawn_token_ids.add(self.gas_token.get("token_id"))
|
|
1028
|
+
gas_amount = float(raw_gas) / 10 ** self.gas_token.get("decimals")
|
|
1073
1029
|
|
|
1074
1030
|
self.DEPOSIT_USDC = 0
|
|
1075
1031
|
self.current_pool_balance = 0
|
|
1076
1032
|
|
|
1077
|
-
if not withdrawn_breakdown:
|
|
1078
|
-
return (True, f"Successfully withdrew {amount} USDC from strategy")
|
|
1079
|
-
|
|
1080
|
-
breakdown_msg = ", ".join(
|
|
1081
|
-
f"{amount:.6f} {symbol} on {chain.capitalize()}"
|
|
1082
|
-
for symbol, chain, amount in withdrawn_breakdown
|
|
1083
|
-
)
|
|
1084
|
-
|
|
1085
1033
|
elapsed_time = time.time() - start_time
|
|
1086
1034
|
logger.info(f"Withdrawal completed successfully in {elapsed_time:.2f} seconds")
|
|
1035
|
+
|
|
1036
|
+
strategy_address = self._get_strategy_wallet_address()
|
|
1037
|
+
breakdown_parts = [f"{usdc_amount:.2f} USDC"]
|
|
1038
|
+
if gas_amount > 0:
|
|
1039
|
+
breakdown_parts.append(
|
|
1040
|
+
f"{gas_amount:.6f} {self.gas_token.get('symbol', 'ETH')}"
|
|
1041
|
+
)
|
|
1042
|
+
|
|
1087
1043
|
return (
|
|
1088
1044
|
True,
|
|
1089
|
-
f"
|
|
1045
|
+
f"Liquidated positions to strategy wallet ({strategy_address}): {', '.join(breakdown_parts)}. "
|
|
1046
|
+
f"Call exit() to transfer to main wallet.",
|
|
1090
1047
|
)
|
|
1091
1048
|
|
|
1092
1049
|
async def exit(self, **kwargs) -> StatusTuple:
|
|
@@ -118,10 +118,6 @@ def strategy():
|
|
|
118
118
|
s.balance_adapter.move_from_strategy_wallet_to_main_wallet = AsyncMock(
|
|
119
119
|
return_value=(True, "Transfer successful (simulated)")
|
|
120
120
|
)
|
|
121
|
-
if hasattr(s.balance_adapter, "wallet_provider"):
|
|
122
|
-
s.balance_adapter.wallet_provider.broadcast_transaction = AsyncMock(
|
|
123
|
-
return_value=(True, {"transaction_hash": "0xDEADBEEF"})
|
|
124
|
-
)
|
|
125
121
|
|
|
126
122
|
if hasattr(s, "ledger_adapter") and s.ledger_adapter:
|
|
127
123
|
# NOTE: The real LedgerClient returns float, not dict!
|
|
@@ -200,10 +196,6 @@ def strategy():
|
|
|
200
196
|
and hasattr(s.brap_adapter, "swap_from_quote")
|
|
201
197
|
):
|
|
202
198
|
s.brap_adapter.swap_from_quote = AsyncMock(return_value=None)
|
|
203
|
-
if hasattr(s, "brap_adapter") and hasattr(s.brap_adapter, "wallet_provider"):
|
|
204
|
-
s.brap_adapter.wallet_provider.broadcast_transaction = AsyncMock(
|
|
205
|
-
return_value=(True, {"transaction_hash": "0xBEEF"})
|
|
206
|
-
)
|
|
207
199
|
|
|
208
200
|
s.DEPOSIT_USDC = 0
|
|
209
201
|
s.usdc_token_info = {
|
|
@@ -41,12 +41,10 @@ async def _status(self) -> StatusDict:
|
|
|
41
41
|
|
|
42
42
|
Strategies typically:
|
|
43
43
|
|
|
44
|
-
1. Build a `DefaultWeb3Service` so every adapter shares a wallet provider.
|
|
45
44
|
2. Instantiate adapters (balance, ledger, protocol specific, etc.).
|
|
46
45
|
3. Register adapters via `self.register_adapters([...])` and keep references as attributes.
|
|
47
46
|
|
|
48
47
|
```python
|
|
49
|
-
from wayfinder_paths.core.services.web3_service import DefaultWeb3Service
|
|
50
48
|
from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
|
|
51
49
|
from wayfinder_paths.adapters.balance_adapter.adapter import BalanceAdapter
|
|
52
50
|
|
|
@@ -57,8 +55,7 @@ class MyStrategy(Strategy):
|
|
|
57
55
|
def __init__(self, config: dict | None = None):
|
|
58
56
|
super().__init__()
|
|
59
57
|
self.config = config or {}
|
|
60
|
-
|
|
61
|
-
balance_adapter = BalanceAdapter(self.config, web3_service=web3_service)
|
|
58
|
+
balance_adapter = BalanceAdapter(self.config)
|
|
62
59
|
self.register_adapters([balance_adapter])
|
|
63
60
|
self.balance_adapter = balance_adapter
|
|
64
61
|
|
|
@@ -76,7 +73,6 @@ class MyStrategy(Strategy):
|
|
|
76
73
|
if not success:
|
|
77
74
|
return (False, "Unable to fetch balances")
|
|
78
75
|
|
|
79
|
-
# Use BalanceAdapter (which leverages LocalTokenTxnService builders) for transfers.
|
|
80
76
|
self.last_deposit = main_token_amount
|
|
81
77
|
return (True, f"Deposited {main_token_amount} tokens")
|
|
82
78
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: wayfinder-paths
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
4
4
|
Summary: Wayfinder Path: strategies and adapters
|
|
5
5
|
Author: Wayfinder
|
|
6
6
|
Author-email: dev@wayfinder.ai
|
|
7
7
|
Requires-Python: >=3.12,<4.0
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
11
|
Requires-Dist: aiohttp (>=3.13.0,<4.0.0)
|
|
11
12
|
Requires-Dist: eth-account (>=0.13.7,<0.14.0)
|
|
12
13
|
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
@@ -275,7 +276,6 @@ Strategies implement trading logic using adapters and the unified client system.
|
|
|
275
276
|
|
|
276
277
|
```python
|
|
277
278
|
# wayfinder_paths/strategies/my_strategy/strategy.py
|
|
278
|
-
from wayfinder_paths.core.services.web3_service import DefaultWeb3Service
|
|
279
279
|
from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
|
|
280
280
|
from wayfinder_paths.adapters.balance_adapter.adapter import BalanceAdapter
|
|
281
281
|
|
|
@@ -291,9 +291,8 @@ class MyStrategy(Strategy):
|
|
|
291
291
|
):
|
|
292
292
|
super().__init__(api_key=api_key) # Pass to base class for auto-discovery
|
|
293
293
|
self.config = config or {}
|
|
294
|
-
web3_service = DefaultWeb3Service(self.config)
|
|
295
294
|
# Adapters automatically discover API key from constructor or config.json
|
|
296
|
-
balance_adapter = BalanceAdapter(self.config
|
|
295
|
+
balance_adapter = BalanceAdapter(self.config)
|
|
297
296
|
self.register_adapters([balance_adapter])
|
|
298
297
|
self.balance_adapter = balance_adapter
|
|
299
298
|
|
|
@@ -311,7 +310,6 @@ class MyStrategy(Strategy):
|
|
|
311
310
|
if not success:
|
|
312
311
|
return (False, "Unable to fetch balances")
|
|
313
312
|
|
|
314
|
-
# Use BalanceAdapter (which leverages LocalTokenTxnService builders) for transfers here.
|
|
315
313
|
self.last_deposit = main_token_amount
|
|
316
314
|
return (True, f"Deposited {main_token_amount} tokens")
|
|
317
315
|
|
|
@@ -344,42 +342,6 @@ The following strategies are available and can be run using the CLI:
|
|
|
344
342
|
|
|
345
343
|
#### Running Strategies
|
|
346
344
|
|
|
347
|
-
```bash
|
|
348
|
-
# Check strategy status
|
|
349
|
-
poetry run python wayfinder_paths/scripts/run_strategy.py \
|
|
350
|
-
--strategy moonwell_wsteth_loop_strategy \
|
|
351
|
-
--main-wallet-label main \
|
|
352
|
-
--strategy-wallet-label moonwell_wsteth_loop_strategy \
|
|
353
|
-
status
|
|
354
|
-
|
|
355
|
-
# Deposit funds (USDC amount, optional ETH for gas)
|
|
356
|
-
poetry run python wayfinder_paths/scripts/run_strategy.py \
|
|
357
|
-
--strategy moonwell_wsteth_loop_strategy \
|
|
358
|
-
--main-wallet-label main \
|
|
359
|
-
--strategy-wallet-label moonwell_wsteth_loop_strategy \
|
|
360
|
-
deposit --usdc 100 --eth 0.01
|
|
361
|
-
|
|
362
|
-
# Run periodic update
|
|
363
|
-
poetry run python wayfinder_paths/scripts/run_strategy.py \
|
|
364
|
-
--strategy moonwell_wsteth_loop_strategy \
|
|
365
|
-
--main-wallet-label main \
|
|
366
|
-
--strategy-wallet-label moonwell_wsteth_loop_strategy \
|
|
367
|
-
update
|
|
368
|
-
|
|
369
|
-
# Withdraw funds (omit --amount for full withdrawal)
|
|
370
|
-
poetry run python wayfinder_paths/scripts/run_strategy.py \
|
|
371
|
-
--strategy moonwell_wsteth_loop_strategy \
|
|
372
|
-
--main-wallet-label main \
|
|
373
|
-
--strategy-wallet-label moonwell_wsteth_loop_strategy \
|
|
374
|
-
withdraw --amount 50
|
|
375
|
-
|
|
376
|
-
# Run in simulation mode (no real transactions)
|
|
377
|
-
poetry run python wayfinder_paths/scripts/run_strategy.py \
|
|
378
|
-
--strategy moonwell_wsteth_loop_strategy \
|
|
379
|
-
--simulation \
|
|
380
|
-
status
|
|
381
|
-
```
|
|
382
|
-
|
|
383
345
|
### Built-in adapters
|
|
384
346
|
|
|
385
347
|
- **BALANCE (BalanceAdapter)**: wraps `WalletClient`/`TokenClient` to read wallet, token, and pool balances and now orchestrates transfers between the main/strategy wallets with ledger bookkeeping. Requires a `Web3Service` so it can share the same wallet provider as the strategy.
|