wayfinder-paths 0.1.15__py3-none-any.whl → 0.1.17__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 +45 -59
- 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.17.dist-info}/METADATA +3 -41
- {wayfinder_paths-0.1.15.dist-info → wayfinder_paths-0.1.17.dist-info}/RECORD +35 -44
- {wayfinder_paths-0.1.15.dist-info → wayfinder_paths-0.1.17.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.17.dist-info}/LICENSE +0 -0
|
@@ -12,12 +12,16 @@ from wayfinder_paths.core.clients.HyperlendClient import (
|
|
|
12
12
|
MarketEntry,
|
|
13
13
|
StableMarketsHeadroomResponse,
|
|
14
14
|
)
|
|
15
|
-
from wayfinder_paths.core.constants.base import DEFAULT_TRANSACTION_TIMEOUT
|
|
16
15
|
from wayfinder_paths.core.constants.hyperlend_abi import (
|
|
17
16
|
POOL_ABI,
|
|
18
17
|
WRAPPED_TOKEN_GATEWAY_ABI,
|
|
19
18
|
)
|
|
20
|
-
from wayfinder_paths.core.
|
|
19
|
+
from wayfinder_paths.core.utils.erc20_service import (
|
|
20
|
+
build_approve_transaction,
|
|
21
|
+
get_token_allowance,
|
|
22
|
+
)
|
|
23
|
+
from wayfinder_paths.core.utils.transaction import send_transaction
|
|
24
|
+
from wayfinder_paths.core.utils.web3 import web3_from_chain_id
|
|
21
25
|
|
|
22
26
|
HYPERLEND_DEFAULTS = {
|
|
23
27
|
"pool": "0x00A89d7a5A02160f20150EbEA7a2b5E4879A1A8b",
|
|
@@ -34,15 +38,16 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
34
38
|
def __init__(
|
|
35
39
|
self,
|
|
36
40
|
config: dict[str, Any],
|
|
37
|
-
|
|
41
|
+
simulation: bool = False,
|
|
42
|
+
strategy_wallet_signing_callback=None,
|
|
38
43
|
) -> None:
|
|
39
44
|
super().__init__("hyperlend_adapter", config)
|
|
40
45
|
cfg = config or {}
|
|
41
46
|
adapter_cfg = cfg.get("hyperlend_adapter") or {}
|
|
42
47
|
|
|
48
|
+
self.simulation = simulation
|
|
49
|
+
self.strategy_wallet_signing_callback = strategy_wallet_signing_callback
|
|
43
50
|
self.hyperlend_client = HyperlendClient()
|
|
44
|
-
self.web3 = web3_service
|
|
45
|
-
self.token_txn_service = web3_service.token_transactions
|
|
46
51
|
|
|
47
52
|
self.strategy_wallet = cfg.get("strategy_wallet") or {}
|
|
48
53
|
self.pool_address = self._checksum(
|
|
@@ -77,20 +82,6 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
77
82
|
buffer_bps=buffer_bps,
|
|
78
83
|
min_buffer_tokens=min_buffer_tokens,
|
|
79
84
|
)
|
|
80
|
-
# Strategies expect a dict with "markets" and "notes"; normalize if API returns a list
|
|
81
|
-
if isinstance(data, list):
|
|
82
|
-
markets: dict[str, Any] = {}
|
|
83
|
-
for i, item in enumerate(data):
|
|
84
|
-
if isinstance(item, dict) and "address" in item:
|
|
85
|
-
markets[item["address"]] = item
|
|
86
|
-
elif isinstance(item, dict):
|
|
87
|
-
markets[str(i)] = item
|
|
88
|
-
data = {"markets": markets, "notes": []}
|
|
89
|
-
elif isinstance(data, dict) and ("markets" not in data or "notes" not in data):
|
|
90
|
-
data = {
|
|
91
|
-
"markets": data.get("markets", {}),
|
|
92
|
-
"notes": data.get("notes", []),
|
|
93
|
-
}
|
|
94
85
|
return True, data
|
|
95
86
|
except Exception as exc:
|
|
96
87
|
return False, str(exc)
|
|
@@ -179,7 +170,7 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
179
170
|
from_address=strategy,
|
|
180
171
|
chain_id=chain_id,
|
|
181
172
|
)
|
|
182
|
-
return await self.
|
|
173
|
+
return await self._send_tx(tx)
|
|
183
174
|
|
|
184
175
|
async def unlend(
|
|
185
176
|
self,
|
|
@@ -200,7 +191,8 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
200
191
|
target=self.gateway_address,
|
|
201
192
|
abi=WRAPPED_TOKEN_GATEWAY_ABI,
|
|
202
193
|
fn_name="withdrawETH",
|
|
203
|
-
args=[self._gateway_first_arg(
|
|
194
|
+
args=[self._gateway_first_arg(
|
|
195
|
+
underlying_token), qty, strategy],
|
|
204
196
|
from_address=strategy,
|
|
205
197
|
chain_id=chain_id,
|
|
206
198
|
)
|
|
@@ -214,12 +206,19 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
214
206
|
from_address=strategy,
|
|
215
207
|
chain_id=chain_id,
|
|
216
208
|
)
|
|
217
|
-
return await self.
|
|
209
|
+
return await self._send_tx(tx)
|
|
218
210
|
|
|
219
211
|
# ------------------------------------------------------------------ #
|
|
220
212
|
# Helpers #
|
|
221
213
|
# ------------------------------------------------------------------ #
|
|
222
214
|
|
|
215
|
+
async def _send_tx(self, tx: dict[str, Any]) -> tuple[bool, Any]:
|
|
216
|
+
"""Send transaction with simulation check."""
|
|
217
|
+
if self.simulation:
|
|
218
|
+
return True, {"simulation": tx}
|
|
219
|
+
txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
220
|
+
return True, txn_hash
|
|
221
|
+
|
|
223
222
|
async def _ensure_allowance(
|
|
224
223
|
self,
|
|
225
224
|
*,
|
|
@@ -229,32 +228,17 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
229
228
|
amount: int,
|
|
230
229
|
chain_id: int,
|
|
231
230
|
) -> tuple[bool, Any]:
|
|
232
|
-
|
|
233
|
-
allowance
|
|
234
|
-
chain, token_address, owner, spender
|
|
235
|
-
)
|
|
236
|
-
if allowance.get("allowance", 0) >= amount:
|
|
231
|
+
allowance = await get_token_allowance(token_address, chain_id, owner, spender)
|
|
232
|
+
if allowance >= amount:
|
|
237
233
|
return True, {}
|
|
238
|
-
|
|
234
|
+
approve_tx = await build_approve_transaction(
|
|
235
|
+
from_address=owner,
|
|
239
236
|
chain_id=chain_id,
|
|
240
237
|
token_address=token_address,
|
|
241
|
-
from_address=owner,
|
|
242
238
|
spender=spender,
|
|
243
239
|
amount=amount,
|
|
244
240
|
)
|
|
245
|
-
|
|
246
|
-
return False, approve_tx
|
|
247
|
-
return await self._broadcast_transaction(approve_tx)
|
|
248
|
-
|
|
249
|
-
async def _execute(self, tx: dict[str, Any]) -> tuple[bool, Any]:
|
|
250
|
-
return await self.web3.broadcast_transaction(
|
|
251
|
-
tx, wait_for_receipt=True, timeout=DEFAULT_TRANSACTION_TIMEOUT
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
async def _broadcast_transaction(self, tx: dict[str, Any]) -> tuple[bool, Any]:
|
|
255
|
-
return await self.web3.evm_transactions.broadcast_transaction(
|
|
256
|
-
tx, wait_for_receipt=True, timeout=DEFAULT_TRANSACTION_TIMEOUT
|
|
257
|
-
)
|
|
241
|
+
return await self._send_tx(approve_tx)
|
|
258
242
|
|
|
259
243
|
async def _encode_call(
|
|
260
244
|
self,
|
|
@@ -268,23 +252,24 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
268
252
|
value: int = 0,
|
|
269
253
|
) -> dict[str, Any]:
|
|
270
254
|
"""Encode calldata without touching network."""
|
|
271
|
-
web3 = self.web3.get_web3(chain_id)
|
|
272
|
-
contract = web3.eth.contract(address=target, abi=abi)
|
|
273
|
-
try:
|
|
274
|
-
data = await getattr(contract.functions, fn_name)(*args).build_transaction(
|
|
275
|
-
{"from": from_address}
|
|
276
|
-
)["data"]
|
|
277
|
-
except ValueError as exc:
|
|
278
|
-
raise ValueError(f"Failed to encode {fn_name}: {exc}") from exc
|
|
279
255
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
256
|
+
async with web3_from_chain_id(chain_id) as web3:
|
|
257
|
+
contract = web3.eth.contract(address=target, abi=abi)
|
|
258
|
+
try:
|
|
259
|
+
data = await getattr(contract.functions, fn_name)(
|
|
260
|
+
*args
|
|
261
|
+
).build_transaction({"from": from_address})["data"]
|
|
262
|
+
except ValueError as exc:
|
|
263
|
+
raise ValueError(f"Failed to encode {fn_name}: {exc}") from exc
|
|
264
|
+
|
|
265
|
+
tx: dict[str, Any] = {
|
|
266
|
+
"chainId": int(chain_id),
|
|
267
|
+
"from": to_checksum_address(from_address),
|
|
268
|
+
"to": to_checksum_address(target),
|
|
269
|
+
"data": data,
|
|
270
|
+
"value": int(value),
|
|
271
|
+
}
|
|
272
|
+
return tx
|
|
288
273
|
|
|
289
274
|
def _strategy_address(self) -> str:
|
|
290
275
|
addr = None
|
|
@@ -307,5 +292,6 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
307
292
|
|
|
308
293
|
def _checksum(self, address: str | None) -> str:
|
|
309
294
|
if not address:
|
|
310
|
-
raise ValueError(
|
|
295
|
+
raise ValueError(
|
|
296
|
+
"Missing required contract address in HyperLend config")
|
|
311
297
|
return to_checksum_address(address)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from types import SimpleNamespace
|
|
2
1
|
from unittest.mock import AsyncMock
|
|
3
2
|
|
|
4
3
|
import pytest
|
|
@@ -16,16 +15,10 @@ class TestHyperlendAdapter:
|
|
|
16
15
|
return mock_client
|
|
17
16
|
|
|
18
17
|
@pytest.fixture
|
|
19
|
-
def
|
|
20
|
-
"""Minimal Web3Service stub for adapter construction."""
|
|
21
|
-
return SimpleNamespace(token_transactions=SimpleNamespace())
|
|
22
|
-
|
|
23
|
-
@pytest.fixture
|
|
24
|
-
def adapter(self, mock_hyperlend_client, mock_web3_service):
|
|
18
|
+
def adapter(self, mock_hyperlend_client):
|
|
25
19
|
"""Create a HyperlendAdapter instance with mocked client for testing"""
|
|
26
20
|
adapter = HyperlendAdapter(
|
|
27
21
|
config={},
|
|
28
|
-
web3_service=mock_web3_service,
|
|
29
22
|
)
|
|
30
23
|
adapter.hyperlend_client = mock_hyperlend_client
|
|
31
24
|
return adapter
|
|
@@ -8,6 +8,7 @@ Adapter for interacting with the [Moonwell](https://moonwell.fi/) lending protoc
|
|
|
8
8
|
## Capabilities
|
|
9
9
|
|
|
10
10
|
The adapter provides the following capabilities:
|
|
11
|
+
|
|
11
12
|
- Lending: Supply and withdraw tokens
|
|
12
13
|
- Borrowing: Borrow and repay tokens
|
|
13
14
|
- Collateral management: Enable/disable markets as collateral
|
|
@@ -17,6 +18,7 @@ The adapter provides the following capabilities:
|
|
|
17
18
|
## Overview
|
|
18
19
|
|
|
19
20
|
The MoonwellAdapter provides functionality for:
|
|
21
|
+
|
|
20
22
|
- **Lending**: Supply tokens to earn yield
|
|
21
23
|
- **Borrowing**: Borrow against collateral
|
|
22
24
|
- **Collateral Management**: Enable/disable markets as collateral
|
|
@@ -25,10 +27,10 @@ The MoonwellAdapter provides functionality for:
|
|
|
25
27
|
|
|
26
28
|
## Supported Markets (Base Chain)
|
|
27
29
|
|
|
28
|
-
| Token
|
|
29
|
-
|
|
30
|
-
| USDC
|
|
31
|
-
| WETH
|
|
30
|
+
| Token | mToken Address | Underlying Address |
|
|
31
|
+
| ------ | -------------------------------------------- | -------------------------------------------- |
|
|
32
|
+
| USDC | `0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22` | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
|
|
33
|
+
| WETH | `0x628ff693426583D9a7FB391E54366292F509D457` | `0x4200000000000000000000000000000000000006` |
|
|
32
34
|
| wstETH | `0x627Fe393Bc6EdDA28e99AE648fD6fF362514304b` | `0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452` |
|
|
33
35
|
|
|
34
36
|
## Protocol Addresses (Base Chain)
|
|
@@ -40,7 +42,6 @@ The MoonwellAdapter provides functionality for:
|
|
|
40
42
|
## Construction
|
|
41
43
|
|
|
42
44
|
```python
|
|
43
|
-
from wayfinder_paths.core.services.web3_service import DefaultWeb3Service
|
|
44
45
|
from wayfinder_paths.adapters.moonwell_adapter import MoonwellAdapter
|
|
45
46
|
|
|
46
47
|
config = {
|
|
@@ -49,12 +50,9 @@ config = {
|
|
|
49
50
|
"chain_id": 8453, # Base chain (default)
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
-
adapter = MoonwellAdapter(config=config, web3_service=web3_service)
|
|
53
|
+
adapter = MoonwellAdapter(config=config)
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
`web3_service` is required so the adapter can share the same wallet provider as the rest of the strategy.
|
|
57
|
-
|
|
58
56
|
## Usage
|
|
59
57
|
|
|
60
58
|
```python
|
|
@@ -102,45 +100,45 @@ await adapter.claim_rewards()
|
|
|
102
100
|
|
|
103
101
|
### Lending Operations
|
|
104
102
|
|
|
105
|
-
| Method
|
|
106
|
-
|
|
107
|
-
| `lend(mtoken, underlying_token, amount)` | Supply tokens to earn yield
|
|
108
|
-
| `unlend(mtoken, amount)`
|
|
103
|
+
| Method | Description |
|
|
104
|
+
| ---------------------------------------- | ----------------------------- |
|
|
105
|
+
| `lend(mtoken, underlying_token, amount)` | Supply tokens to earn yield |
|
|
106
|
+
| `unlend(mtoken, amount)` | Withdraw by redeeming mTokens |
|
|
109
107
|
|
|
110
108
|
### Borrowing Operations
|
|
111
109
|
|
|
112
|
-
| Method
|
|
113
|
-
|
|
114
|
-
| `borrow(mtoken, amount)`
|
|
115
|
-
| `repay(mtoken, underlying_token, amount)` | Repay borrowed tokens
|
|
110
|
+
| Method | Description |
|
|
111
|
+
| ----------------------------------------- | ------------------------ |
|
|
112
|
+
| `borrow(mtoken, amount)` | Borrow underlying tokens |
|
|
113
|
+
| `repay(mtoken, underlying_token, amount)` | Repay borrowed tokens |
|
|
116
114
|
|
|
117
115
|
### Collateral Management
|
|
118
116
|
|
|
119
|
-
| Method
|
|
120
|
-
|
|
121
|
-
| `set_collateral(mtoken)`
|
|
122
|
-
| `remove_collateral(mtoken)` | Disable market as collateral (exitMarket)
|
|
117
|
+
| Method | Description |
|
|
118
|
+
| --------------------------- | ------------------------------------------ |
|
|
119
|
+
| `set_collateral(mtoken)` | Enable market as collateral (enterMarkets) |
|
|
120
|
+
| `remove_collateral(mtoken)` | Disable market as collateral (exitMarket) |
|
|
123
121
|
|
|
124
122
|
### Position & Market Data
|
|
125
123
|
|
|
126
|
-
| Method
|
|
127
|
-
|
|
128
|
-
| `get_pos(mtoken, account)`
|
|
129
|
-
| `get_collateral_factor(mtoken)`
|
|
130
|
-
| `get_apy(mtoken, apy_type)`
|
|
131
|
-
| `get_borrowable_amount(account)`
|
|
124
|
+
| Method | Description |
|
|
125
|
+
| ------------------------------------------ | -------------------------------------------------- |
|
|
126
|
+
| `get_pos(mtoken, account)` | Get position data (balances, debt, rewards) |
|
|
127
|
+
| `get_collateral_factor(mtoken)` | Get collateral factor (LTV) |
|
|
128
|
+
| `get_apy(mtoken, apy_type)` | Get supply or borrow APY |
|
|
129
|
+
| `get_borrowable_amount(account)` | Get max borrowable in USD |
|
|
132
130
|
| `max_withdrawable_mtoken(mtoken, account)` | Calculate safe withdrawal amount via binary search |
|
|
133
131
|
|
|
134
132
|
### Rewards
|
|
135
133
|
|
|
136
|
-
| Method
|
|
137
|
-
|
|
134
|
+
| Method | Description |
|
|
135
|
+
| -------------------------------- | --------------------------------------------- |
|
|
138
136
|
| `claim_rewards(min_rewards_usd)` | Claim WELL rewards (skips if below threshold) |
|
|
139
137
|
|
|
140
138
|
### Utilities
|
|
141
139
|
|
|
142
|
-
| Method
|
|
143
|
-
|
|
140
|
+
| Method | Description |
|
|
141
|
+
| ------------------ | ---------------- |
|
|
144
142
|
| `wrap_eth(amount)` | Wrap ETH to WETH |
|
|
145
143
|
|
|
146
144
|
All methods return `(success: bool, payload: Any)` tuples. On failure the payload is an error string.
|