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
|
@@ -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,
|
|
@@ -214,12 +205,19 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
214
205
|
from_address=strategy,
|
|
215
206
|
chain_id=chain_id,
|
|
216
207
|
)
|
|
217
|
-
return await self.
|
|
208
|
+
return await self._send_tx(tx)
|
|
218
209
|
|
|
219
210
|
# ------------------------------------------------------------------ #
|
|
220
211
|
# Helpers #
|
|
221
212
|
# ------------------------------------------------------------------ #
|
|
222
213
|
|
|
214
|
+
async def _send_tx(self, tx: dict[str, Any]) -> tuple[bool, Any]:
|
|
215
|
+
"""Send transaction with simulation check."""
|
|
216
|
+
if self.simulation:
|
|
217
|
+
return True, {"simulation": tx}
|
|
218
|
+
txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
219
|
+
return True, txn_hash
|
|
220
|
+
|
|
223
221
|
async def _ensure_allowance(
|
|
224
222
|
self,
|
|
225
223
|
*,
|
|
@@ -229,32 +227,17 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
229
227
|
amount: int,
|
|
230
228
|
chain_id: int,
|
|
231
229
|
) -> tuple[bool, Any]:
|
|
232
|
-
|
|
233
|
-
allowance = await self.token_txn_service.read_erc20_allowance(
|
|
234
|
-
chain, token_address, owner, spender
|
|
235
|
-
)
|
|
230
|
+
allowance = await get_token_allowance(token_address, chain_id, owner, spender)
|
|
236
231
|
if allowance.get("allowance", 0) >= amount:
|
|
237
232
|
return True, {}
|
|
238
|
-
|
|
233
|
+
approve_tx = await build_approve_transaction(
|
|
234
|
+
from_address=owner,
|
|
239
235
|
chain_id=chain_id,
|
|
240
236
|
token_address=token_address,
|
|
241
|
-
from_address=owner,
|
|
242
237
|
spender=spender,
|
|
243
238
|
amount=amount,
|
|
244
239
|
)
|
|
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
|
-
)
|
|
240
|
+
return await self._send_tx(approve_tx)
|
|
258
241
|
|
|
259
242
|
async def _encode_call(
|
|
260
243
|
self,
|
|
@@ -268,23 +251,24 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
268
251
|
value: int = 0,
|
|
269
252
|
) -> dict[str, Any]:
|
|
270
253
|
"""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
254
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
255
|
+
async with web3_from_chain_id(chain_id) as web3:
|
|
256
|
+
contract = web3.eth.contract(address=target, abi=abi)
|
|
257
|
+
try:
|
|
258
|
+
data = await getattr(contract.functions, fn_name)(
|
|
259
|
+
*args
|
|
260
|
+
).build_transaction({"from": from_address})["data"]
|
|
261
|
+
except ValueError as exc:
|
|
262
|
+
raise ValueError(f"Failed to encode {fn_name}: {exc}") from exc
|
|
263
|
+
|
|
264
|
+
tx: dict[str, Any] = {
|
|
265
|
+
"chainId": int(chain_id),
|
|
266
|
+
"from": to_checksum_address(from_address),
|
|
267
|
+
"to": to_checksum_address(target),
|
|
268
|
+
"data": data,
|
|
269
|
+
"value": int(value),
|
|
270
|
+
}
|
|
271
|
+
return tx
|
|
288
272
|
|
|
289
273
|
def _strategy_address(self) -> str:
|
|
290
274
|
addr = None
|
|
@@ -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.
|