wayfinder-paths 0.1.4__py3-none-any.whl → 0.1.6__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/CONFIG_GUIDE.md +14 -14
- wayfinder_paths/__init__.py +4 -3
- wayfinder_paths/adapters/balance_adapter/README.md +10 -10
- wayfinder_paths/adapters/balance_adapter/adapter.py +10 -9
- wayfinder_paths/adapters/balance_adapter/examples.json +1 -1
- wayfinder_paths/adapters/brap_adapter/README.md +1 -1
- wayfinder_paths/adapters/brap_adapter/adapter.py +28 -21
- wayfinder_paths/adapters/hyperlend_adapter/adapter.py +33 -26
- wayfinder_paths/adapters/ledger_adapter/README.md +26 -39
- wayfinder_paths/adapters/ledger_adapter/adapter.py +78 -75
- wayfinder_paths/adapters/ledger_adapter/examples.json +10 -4
- wayfinder_paths/adapters/ledger_adapter/manifest.yaml +4 -4
- wayfinder_paths/adapters/ledger_adapter/test_adapter.py +31 -26
- wayfinder_paths/adapters/pool_adapter/README.md +1 -13
- wayfinder_paths/adapters/pool_adapter/adapter.py +12 -19
- wayfinder_paths/adapters/token_adapter/adapter.py +8 -4
- wayfinder_paths/core/__init__.py +9 -4
- wayfinder_paths/core/adapters/BaseAdapter.py +20 -3
- wayfinder_paths/core/adapters/models.py +41 -0
- wayfinder_paths/core/clients/BRAPClient.py +21 -2
- wayfinder_paths/core/clients/ClientManager.py +42 -63
- wayfinder_paths/core/clients/HyperlendClient.py +46 -5
- wayfinder_paths/core/clients/LedgerClient.py +350 -124
- wayfinder_paths/core/clients/PoolClient.py +51 -19
- wayfinder_paths/core/clients/SimulationClient.py +16 -4
- wayfinder_paths/core/clients/TokenClient.py +34 -18
- wayfinder_paths/core/clients/TransactionClient.py +18 -2
- wayfinder_paths/core/clients/WalletClient.py +35 -4
- wayfinder_paths/core/clients/WayfinderClient.py +16 -5
- wayfinder_paths/core/clients/protocols.py +69 -62
- wayfinder_paths/core/clients/sdk_example.py +0 -5
- wayfinder_paths/core/config.py +192 -103
- wayfinder_paths/core/constants/base.py +17 -0
- wayfinder_paths/core/engine/{VaultJob.py → StrategyJob.py} +25 -19
- wayfinder_paths/core/engine/__init__.py +2 -2
- wayfinder_paths/core/services/base.py +6 -4
- wayfinder_paths/core/services/local_evm_txn.py +3 -2
- wayfinder_paths/core/settings.py +2 -2
- wayfinder_paths/core/strategies/Strategy.py +135 -38
- wayfinder_paths/core/strategies/descriptors.py +1 -0
- wayfinder_paths/core/utils/evm_helpers.py +12 -10
- wayfinder_paths/core/wallets/README.md +3 -3
- wayfinder_paths/core/wallets/WalletManager.py +3 -3
- wayfinder_paths/run_strategy.py +26 -24
- wayfinder_paths/scripts/make_wallets.py +6 -6
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +6 -6
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +36 -156
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +6 -6
- wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +11 -11
- wayfinder_paths/strategies/stablecoin_yield_strategy/manifest.yaml +1 -1
- wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +92 -92
- wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +6 -6
- wayfinder_paths/templates/adapter/README.md +1 -1
- wayfinder_paths/templates/adapter/test_adapter.py +1 -1
- wayfinder_paths/templates/strategy/README.md +4 -4
- wayfinder_paths/templates/strategy/test_strategy.py +7 -7
- wayfinder_paths/tests/test_test_coverage.py +5 -5
- {wayfinder_paths-0.1.4.dist-info → wayfinder_paths-0.1.6.dist-info}/METADATA +46 -47
- {wayfinder_paths-0.1.4.dist-info → wayfinder_paths-0.1.6.dist-info}/RECORD +61 -60
- {wayfinder_paths-0.1.4.dist-info → wayfinder_paths-0.1.6.dist-info}/LICENSE +0 -0
- {wayfinder_paths-0.1.4.dist-info → wayfinder_paths-0.1.6.dist-info}/WHEEL +0 -0
wayfinder_paths/CONFIG_GUIDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Configuration Guide
|
|
2
2
|
|
|
3
|
-
This guide explains how to configure your
|
|
3
|
+
This guide explains how to configure your strategies for local testing.
|
|
4
4
|
|
|
5
5
|
## Quick Setup
|
|
6
6
|
|
|
@@ -64,7 +64,7 @@ cp wayfinder_paths/config.example.json config.json
|
|
|
64
64
|
|
|
65
65
|
**Other Optional fields:**
|
|
66
66
|
- `user.main_wallet_address` - Override auto-loaded main wallet
|
|
67
|
-
- `user.
|
|
67
|
+
- `user.strategy_wallet_address` - Override auto-loaded strategy wallet
|
|
68
68
|
|
|
69
69
|
**Security Note:** Never commit `config.json` to version control. Add it to `.gitignore`.
|
|
70
70
|
|
|
@@ -74,7 +74,7 @@ These are managed automatically by Wayfinder:
|
|
|
74
74
|
- `api_base_url` - Wayfinder backend API endpoint
|
|
75
75
|
- `wallets_path` - Location of generated wallets.json
|
|
76
76
|
- `job_id` - Auto-generated by Wayfinder
|
|
77
|
-
- `job_type` - Set to "
|
|
77
|
+
- `job_type` - Set to "strategy"
|
|
78
78
|
|
|
79
79
|
## Strategy Configuration
|
|
80
80
|
|
|
@@ -125,8 +125,8 @@ Each strategy should have its own dedicated wallet for isolation and security. T
|
|
|
125
125
|
When you run a strategy:
|
|
126
126
|
1. The system uses the strategy directory name (e.g., `hyperlend_stable_yield_strategy`) to look up a wallet
|
|
127
127
|
2. It searches `wallets.json` for a wallet with a matching `label`
|
|
128
|
-
3. If found, that wallet is used as the strategy's
|
|
129
|
-
4. Falls back to `
|
|
128
|
+
3. If found, that wallet is used as the strategy's dedicated wallet
|
|
129
|
+
4. Falls back to `strategy_wallet_address` from config if explicitly provided
|
|
130
130
|
|
|
131
131
|
### Creating a Strategy with Wallet
|
|
132
132
|
|
|
@@ -188,11 +188,11 @@ Strategies access wallets the same way as before:
|
|
|
188
188
|
|
|
189
189
|
```python
|
|
190
190
|
# In strategy code
|
|
191
|
-
|
|
191
|
+
strategy_address = self.config.get("strategy_wallet").get("address")
|
|
192
192
|
main_address = self.config.get("main_wallet").get("address")
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
-
The
|
|
195
|
+
The strategy wallet is automatically populated from the wallet with label matching the strategy directory name.
|
|
196
196
|
|
|
197
197
|
## Loading Configuration
|
|
198
198
|
|
|
@@ -206,14 +206,14 @@ For programmatic use:
|
|
|
206
206
|
|
|
207
207
|
```python
|
|
208
208
|
from pathlib import Path
|
|
209
|
-
from core.config import
|
|
209
|
+
from core.config import StrategyJobConfig
|
|
210
210
|
import json
|
|
211
211
|
|
|
212
212
|
# Load from file
|
|
213
213
|
with open("config.json") as f:
|
|
214
214
|
config_data = json.load(f)
|
|
215
215
|
|
|
216
|
-
config =
|
|
216
|
+
config = StrategyJobConfig.from_dict(config_data)
|
|
217
217
|
|
|
218
218
|
# Configuration now has:
|
|
219
219
|
# - config.user.username & password (for Wayfinder backend)
|
|
@@ -223,13 +223,13 @@ config = VaultConfig.from_dict(config_data)
|
|
|
223
223
|
|
|
224
224
|
## Wallet Abstraction
|
|
225
225
|
|
|
226
|
-
The
|
|
226
|
+
The strategy system supports multiple wallet types through a wallet abstraction layer. By default, adapters use local private keys (self-custodial wallets), but you can inject custom wallet providers for custodial wallets like Privy or Turnkey.
|
|
227
227
|
|
|
228
228
|
### Default Behavior (Local Wallets)
|
|
229
229
|
|
|
230
230
|
By default, adapters use `LocalWalletProvider` which resolves private keys from:
|
|
231
231
|
- `wallets.json` (matched by address)
|
|
232
|
-
- Environment variables (`PRIVATE_KEY`, `
|
|
232
|
+
- Environment variables (`PRIVATE_KEY`, `PRIVATE_KEY_STRATEGY`)
|
|
233
233
|
- Wallet config in `config.json`
|
|
234
234
|
|
|
235
235
|
No code changes are required - existing strategies continue to work.
|
|
@@ -264,7 +264,7 @@ See `core/wallets/README.md` for details on implementing custom wallet providers
|
|
|
264
264
|
|
|
265
265
|
## Authentication with Wayfinder Backend
|
|
266
266
|
|
|
267
|
-
Wayfinder
|
|
267
|
+
Wayfinder Paths supports **dual authentication** for different use cases:
|
|
268
268
|
|
|
269
269
|
### 1. Service Account Authentication (API Key)
|
|
270
270
|
|
|
@@ -318,7 +318,7 @@ export WAYFINDER_API_KEY="sk_live_abc123..."
|
|
|
318
318
|
The `username` and `password` in your config authenticate with the Wayfinder backend to access:
|
|
319
319
|
- Wallet management
|
|
320
320
|
- Transaction signing services
|
|
321
|
-
-
|
|
321
|
+
- Strategy execution services
|
|
322
322
|
|
|
323
323
|
```json
|
|
324
324
|
{
|
|
@@ -343,7 +343,7 @@ The `username` and `password` in your config authenticate with the Wayfinder bac
|
|
|
343
343
|
|
|
344
344
|
## Configuration in Strategies
|
|
345
345
|
|
|
346
|
-
Strategies receive configuration automatically through
|
|
346
|
+
Strategies receive configuration automatically through StrategyJob:
|
|
347
347
|
|
|
348
348
|
```python
|
|
349
349
|
from core.strategies.Strategy import Strategy
|
wayfinder_paths/__init__.py
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
"""Wayfinder Path - Trading strategies and adapters for automated
|
|
1
|
+
"""Wayfinder Path - Trading strategies and adapters for automated strategy management"""
|
|
2
2
|
|
|
3
3
|
__version__ = "0.1.0"
|
|
4
4
|
|
|
5
5
|
# Re-export commonly used items for convenience
|
|
6
6
|
from wayfinder_paths.core import (
|
|
7
7
|
BaseAdapter,
|
|
8
|
+
LiquidationResult,
|
|
8
9
|
StatusDict,
|
|
9
10
|
StatusTuple,
|
|
10
11
|
Strategy,
|
|
11
|
-
|
|
12
|
+
StrategyJob,
|
|
12
13
|
)
|
|
13
14
|
|
|
14
15
|
__all__ = [
|
|
@@ -17,5 +18,5 @@ __all__ = [
|
|
|
17
18
|
"Strategy",
|
|
18
19
|
"StatusDict",
|
|
19
20
|
"StatusTuple",
|
|
20
|
-
"
|
|
21
|
+
"StrategyJob",
|
|
21
22
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Balance Adapter
|
|
2
2
|
|
|
3
|
-
Adapter that exposes wallet, token, and pool balances backed by `WalletClient`/`TokenClient` and now orchestrates transfers between the configured main/
|
|
3
|
+
Adapter that exposes wallet, token, and pool balances backed by `WalletClient`/`TokenClient` and now orchestrates transfers between the configured main/strategy wallets (with ledger bookkeeping).
|
|
4
4
|
|
|
5
5
|
- Entrypoint: `adapters.balance_adapter.adapter.BalanceAdapter`
|
|
6
6
|
- Manifest: `manifest.yaml`
|
|
@@ -41,7 +41,7 @@ Fetches the amount supplied to a specific pool, using the `/wallets/pool-balance
|
|
|
41
41
|
success, amount = await balance.get_pool_balance(
|
|
42
42
|
pool_address="0xPool",
|
|
43
43
|
chain_id=8453,
|
|
44
|
-
user_address=config["
|
|
44
|
+
user_address=config["strategy_wallet"]["address"],
|
|
45
45
|
)
|
|
46
46
|
```
|
|
47
47
|
|
|
@@ -50,27 +50,27 @@ Returns the enriched token balance payload Wayfinder exposes (including USD valu
|
|
|
50
50
|
|
|
51
51
|
```python
|
|
52
52
|
success, snapshot = await balance.get_all_balances(
|
|
53
|
-
wallet_address=config["
|
|
53
|
+
wallet_address=config["strategy_wallet"]["address"],
|
|
54
54
|
enrich=True,
|
|
55
55
|
)
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
### `
|
|
59
|
-
Sends the specified token from the configured `main_wallet` to the
|
|
58
|
+
### `move_from_main_wallet_to_strategy_wallet(token_id: str, amount: float, strategy_name="unknown", skip_ledger=False)`
|
|
59
|
+
Sends the specified token from the configured `main_wallet` to the strategy wallet, records the ledger deposit (unless `skip_ledger=True`), and returns the `(success, tx_result)` tuple from the underlying send helper.
|
|
60
60
|
|
|
61
61
|
```python
|
|
62
|
-
success, tx = await balance.
|
|
62
|
+
success, tx = await balance.move_from_main_wallet_to_strategy_wallet(
|
|
63
63
|
token_id="usd-coin-base",
|
|
64
64
|
amount=1.5,
|
|
65
65
|
strategy_name="MyStrategy",
|
|
66
66
|
)
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
### `
|
|
70
|
-
Mirrors the previous method but withdraws from the
|
|
69
|
+
### `move_from_strategy_wallet_to_main_wallet(token_id: str, amount: float, strategy_name="unknown", skip_ledger=False)`
|
|
70
|
+
Mirrors the previous method but withdraws from the strategy wallet back to the main wallet while recording a ledger withdrawal entry.
|
|
71
71
|
|
|
72
72
|
```python
|
|
73
|
-
await balance.
|
|
73
|
+
await balance.move_from_strategy_wallet_to_main_wallet(
|
|
74
74
|
token_id="usd-coin-base",
|
|
75
75
|
amount=0.75,
|
|
76
76
|
strategy_name="MyStrategy",
|
|
@@ -94,7 +94,7 @@ class MyStrategy(Strategy):
|
|
|
94
94
|
success, pool_balance = await self.balance_adapter.get_pool_balance(
|
|
95
95
|
pool_address=self.current_pool["address"],
|
|
96
96
|
chain_id=self.current_pool["chain"]["id"],
|
|
97
|
-
user_address=self.config["
|
|
97
|
+
user_address=self.config["strategy_wallet"]["address"],
|
|
98
98
|
)
|
|
99
99
|
return {"portfolio_value": float(pool_balance or 0), ...}
|
|
100
100
|
```
|
|
@@ -5,6 +5,7 @@ from wayfinder_paths.adapters.token_adapter.adapter import TokenAdapter
|
|
|
5
5
|
from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
|
|
6
6
|
from wayfinder_paths.core.clients.TokenClient import TokenClient
|
|
7
7
|
from wayfinder_paths.core.clients.WalletClient import WalletClient
|
|
8
|
+
from wayfinder_paths.core.constants.base import DEFAULT_TRANSACTION_TIMEOUT
|
|
8
9
|
from wayfinder_paths.core.services.base import Web3Service
|
|
9
10
|
from wayfinder_paths.core.settings import settings
|
|
10
11
|
from wayfinder_paths.core.utils.evm_helpers import resolve_chain_id
|
|
@@ -44,7 +45,7 @@ class BalanceAdapter(BaseAdapter):
|
|
|
44
45
|
*,
|
|
45
46
|
token_id: str,
|
|
46
47
|
wallet_address: str,
|
|
47
|
-
) -> tuple[bool,
|
|
48
|
+
) -> tuple[bool, str | int]:
|
|
48
49
|
"""Get token balance for a wallet."""
|
|
49
50
|
try:
|
|
50
51
|
data = await self.wallet_client.get_token_balance_for_wallet(
|
|
@@ -55,37 +56,37 @@ class BalanceAdapter(BaseAdapter):
|
|
|
55
56
|
except Exception as e:
|
|
56
57
|
return (False, str(e))
|
|
57
58
|
|
|
58
|
-
async def
|
|
59
|
+
async def move_from_main_wallet_to_strategy_wallet(
|
|
59
60
|
self,
|
|
60
61
|
token_id: str,
|
|
61
62
|
amount: float,
|
|
62
63
|
strategy_name: str = "unknown",
|
|
63
64
|
skip_ledger: bool = False,
|
|
64
65
|
) -> tuple[bool, Any]:
|
|
65
|
-
"""Move funds from the configured main wallet into the
|
|
66
|
+
"""Move funds from the configured main wallet into the strategy wallet."""
|
|
66
67
|
return await self._move_between_wallets(
|
|
67
68
|
token_id=token_id,
|
|
68
69
|
amount=amount,
|
|
69
70
|
from_wallet=self.config.get("main_wallet"),
|
|
70
|
-
to_wallet=self.config.get("
|
|
71
|
+
to_wallet=self.config.get("strategy_wallet"),
|
|
71
72
|
ledger_method=self.ledger_adapter.record_deposit,
|
|
72
73
|
ledger_wallet="to",
|
|
73
74
|
strategy_name=strategy_name,
|
|
74
75
|
skip_ledger=skip_ledger,
|
|
75
76
|
)
|
|
76
77
|
|
|
77
|
-
async def
|
|
78
|
+
async def move_from_strategy_wallet_to_main_wallet(
|
|
78
79
|
self,
|
|
79
80
|
token_id: str,
|
|
80
81
|
amount: float,
|
|
81
82
|
strategy_name: str = "unknown",
|
|
82
83
|
skip_ledger: bool = False,
|
|
83
84
|
) -> tuple[bool, Any]:
|
|
84
|
-
"""Move funds from the
|
|
85
|
+
"""Move funds from the strategy wallet back into the main wallet."""
|
|
85
86
|
return await self._move_between_wallets(
|
|
86
87
|
token_id=token_id,
|
|
87
88
|
amount=amount,
|
|
88
|
-
from_wallet=self.config.get("
|
|
89
|
+
from_wallet=self.config.get("strategy_wallet"),
|
|
89
90
|
to_wallet=self.config.get("main_wallet"),
|
|
90
91
|
ledger_method=self.ledger_adapter.record_withdrawal,
|
|
91
92
|
ledger_wallet="from",
|
|
@@ -111,7 +112,7 @@ class BalanceAdapter(BaseAdapter):
|
|
|
111
112
|
from_address = self._wallet_address(from_wallet)
|
|
112
113
|
to_address = self._wallet_address(to_wallet)
|
|
113
114
|
if not from_address or not to_address:
|
|
114
|
-
return False, "main_wallet or
|
|
115
|
+
return False, "main_wallet or strategy_wallet missing"
|
|
115
116
|
|
|
116
117
|
token_info = await self.token_client.get_token_details(token_id)
|
|
117
118
|
if not token_info:
|
|
@@ -132,7 +133,7 @@ class BalanceAdapter(BaseAdapter):
|
|
|
132
133
|
broadcast_result = (True, {"dry_run": True, "transaction": tx})
|
|
133
134
|
else:
|
|
134
135
|
broadcast_result = await self.wallet_provider.broadcast_transaction(
|
|
135
|
-
tx, wait_for_receipt=True, timeout=
|
|
136
|
+
tx, wait_for_receipt=True, timeout=DEFAULT_TRANSACTION_TIMEOUT
|
|
136
137
|
)
|
|
137
138
|
|
|
138
139
|
if broadcast_result[0] and not skip_ledger and ledger_method is not None:
|
|
@@ -240,7 +240,7 @@ All methods return a tuple of `(success: bool, data: Any)` where:
|
|
|
240
240
|
Run the adapter tests:
|
|
241
241
|
|
|
242
242
|
```bash
|
|
243
|
-
pytest wayfinder_paths/
|
|
243
|
+
pytest wayfinder_paths/adapters/brap_adapter/test_adapter.py -v
|
|
244
244
|
```
|
|
245
245
|
|
|
246
246
|
## Dependencies
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from typing import Any
|
|
2
4
|
|
|
3
5
|
from eth_utils import to_checksum_address
|
|
@@ -5,10 +7,16 @@ from eth_utils import to_checksum_address
|
|
|
5
7
|
from wayfinder_paths.adapters.ledger_adapter.adapter import LedgerAdapter
|
|
6
8
|
from wayfinder_paths.adapters.token_adapter.adapter import TokenAdapter
|
|
7
9
|
from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
|
|
8
|
-
from wayfinder_paths.core.
|
|
9
|
-
from wayfinder_paths.core.clients.
|
|
10
|
+
from wayfinder_paths.core.adapters.models import SWAP
|
|
11
|
+
from wayfinder_paths.core.clients.BRAPClient import BRAPClient, BRAPQuote
|
|
12
|
+
from wayfinder_paths.core.clients.LedgerClient import TransactionRecord
|
|
13
|
+
from wayfinder_paths.core.clients.SimulationClient import (
|
|
14
|
+
SimulationClient,
|
|
15
|
+
SimulationResult,
|
|
16
|
+
)
|
|
10
17
|
from wayfinder_paths.core.clients.TokenClient import TokenClient
|
|
11
18
|
from wayfinder_paths.core.constants import DEFAULT_SLIPPAGE
|
|
19
|
+
from wayfinder_paths.core.constants.base import DEFAULT_TRANSACTION_TIMEOUT
|
|
12
20
|
from wayfinder_paths.core.services.base import Web3Service
|
|
13
21
|
from wayfinder_paths.core.settings import settings
|
|
14
22
|
|
|
@@ -61,7 +69,7 @@ class BRAPAdapter(BaseAdapter):
|
|
|
61
69
|
amount: str,
|
|
62
70
|
slippage: float | None = None,
|
|
63
71
|
wayfinder_fee: float | None = None,
|
|
64
|
-
) -> tuple[bool,
|
|
72
|
+
) -> tuple[bool, BRAPQuote | str]:
|
|
65
73
|
"""
|
|
66
74
|
Get a quote for a cross-chain swap operation.
|
|
67
75
|
|
|
@@ -107,7 +115,7 @@ class BRAPAdapter(BaseAdapter):
|
|
|
107
115
|
amount: str,
|
|
108
116
|
slippage: float | None = None,
|
|
109
117
|
wayfinder_fee: float | None = None,
|
|
110
|
-
) -> tuple[bool, Any]:
|
|
118
|
+
) -> tuple[bool, dict[str, Any] | str]:
|
|
111
119
|
"""
|
|
112
120
|
Get the best available quote for a swap operation.
|
|
113
121
|
|
|
@@ -597,7 +605,7 @@ class BRAPAdapter(BaseAdapter):
|
|
|
597
605
|
return await self.wallet_provider.broadcast_transaction(
|
|
598
606
|
transaction,
|
|
599
607
|
wait_for_receipt=True,
|
|
600
|
-
timeout=
|
|
608
|
+
timeout=DEFAULT_TRANSACTION_TIMEOUT,
|
|
601
609
|
)
|
|
602
610
|
|
|
603
611
|
async def _record_swap_operation(
|
|
@@ -608,7 +616,7 @@ class BRAPAdapter(BaseAdapter):
|
|
|
608
616
|
quote: dict[str, Any],
|
|
609
617
|
broadcast_response: dict[str, Any] | Any,
|
|
610
618
|
strategy_name: str | None = None,
|
|
611
|
-
) -> Any:
|
|
619
|
+
) -> TransactionRecord | dict[str, Any]:
|
|
612
620
|
from_amount_usd = quote.get("from_amount_usd")
|
|
613
621
|
if from_amount_usd is None:
|
|
614
622
|
from_amount_usd = await self._token_amount_usd(
|
|
@@ -622,23 +630,22 @@ class BRAPAdapter(BaseAdapter):
|
|
|
622
630
|
)
|
|
623
631
|
|
|
624
632
|
response = broadcast_response if isinstance(broadcast_response, dict) else {}
|
|
625
|
-
|
|
626
|
-
"
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
"
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
}
|
|
633
|
+
operation_data = SWAP(
|
|
634
|
+
from_token_id=from_token.get("id"),
|
|
635
|
+
to_token_id=to_token.get("id"),
|
|
636
|
+
from_amount=quote.get("input_amount"),
|
|
637
|
+
to_amount=quote.get("output_amount"),
|
|
638
|
+
from_amount_usd=from_amount_usd or 0,
|
|
639
|
+
to_amount_usd=to_amount_usd or 0,
|
|
640
|
+
transaction_hash=response.get("transaction_hash"),
|
|
641
|
+
transaction_status=response.get("transaction_status"),
|
|
642
|
+
transaction_receipt=response.get("transaction_receipt"),
|
|
643
|
+
)
|
|
637
644
|
|
|
638
645
|
try:
|
|
639
646
|
success, ledger_response = await self.ledger_adapter.record_operation(
|
|
640
647
|
wallet_address=wallet_address,
|
|
641
|
-
operation_data=
|
|
648
|
+
operation_data=operation_data,
|
|
642
649
|
usd_value=from_amount_usd or 0,
|
|
643
650
|
strategy_name=strategy_name,
|
|
644
651
|
)
|
|
@@ -650,7 +657,7 @@ class BRAPAdapter(BaseAdapter):
|
|
|
650
657
|
except Exception as exc: # noqa: BLE001
|
|
651
658
|
self.logger.warning(f"Ledger swap record raised: {exc}", quote=quote)
|
|
652
659
|
|
|
653
|
-
return
|
|
660
|
+
return operation_data.model_dump(mode="json")
|
|
654
661
|
|
|
655
662
|
async def _token_amount_usd(
|
|
656
663
|
self, token_info: dict[str, Any], raw_amount: Any
|
|
@@ -676,7 +683,7 @@ class BRAPAdapter(BaseAdapter):
|
|
|
676
683
|
from_address: str,
|
|
677
684
|
chain_id: int,
|
|
678
685
|
quote: dict[str, Any],
|
|
679
|
-
) ->
|
|
686
|
+
) -> SimulationResult:
|
|
680
687
|
client = await self._get_simulation_client()
|
|
681
688
|
initial_balances = {"native": "5000000000000000000"}
|
|
682
689
|
if from_token.get("address"):
|
|
@@ -5,8 +5,15 @@ from typing import Any
|
|
|
5
5
|
from eth_utils import to_checksum_address
|
|
6
6
|
|
|
7
7
|
from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
|
|
8
|
-
from wayfinder_paths.core.clients.HyperlendClient import
|
|
8
|
+
from wayfinder_paths.core.clients.HyperlendClient import (
|
|
9
|
+
AssetsView,
|
|
10
|
+
HyperlendClient,
|
|
11
|
+
LendRateHistory,
|
|
12
|
+
MarketEntry,
|
|
13
|
+
StableMarket,
|
|
14
|
+
)
|
|
9
15
|
from wayfinder_paths.core.clients.SimulationClient import SimulationClient
|
|
16
|
+
from wayfinder_paths.core.constants.base import DEFAULT_TRANSACTION_TIMEOUT
|
|
10
17
|
from wayfinder_paths.core.constants.hyperlend_abi import (
|
|
11
18
|
POOL_ABI,
|
|
12
19
|
WRAPPED_TOKEN_GATEWAY_ABI,
|
|
@@ -43,7 +50,7 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
43
50
|
self.web3 = web3_service
|
|
44
51
|
self.token_txn_service = web3_service.token_transactions
|
|
45
52
|
|
|
46
|
-
self.
|
|
53
|
+
self.strategy_wallet = cfg.get("strategy_wallet") or {}
|
|
47
54
|
self.pool_address = self._checksum(
|
|
48
55
|
adapter_cfg.get("pool_address") or HYPERLEND_DEFAULTS["pool"]
|
|
49
56
|
)
|
|
@@ -70,7 +77,7 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
70
77
|
buffer_bps: int | None = None,
|
|
71
78
|
min_buffer_tokens: float | None = None,
|
|
72
79
|
is_stable_symbol: bool | None = None,
|
|
73
|
-
) -> tuple[bool,
|
|
80
|
+
) -> tuple[bool, list[StableMarket] | str]:
|
|
74
81
|
try:
|
|
75
82
|
data = await self.hyperlend_client.get_stable_markets(
|
|
76
83
|
chain_id=chain_id,
|
|
@@ -85,7 +92,7 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
85
92
|
|
|
86
93
|
async def get_assets_view(
|
|
87
94
|
self, chain_id: int, user_address: str
|
|
88
|
-
) -> tuple[bool,
|
|
95
|
+
) -> tuple[bool, AssetsView | str]:
|
|
89
96
|
try:
|
|
90
97
|
data = await self.hyperlend_client.get_assets_view(
|
|
91
98
|
chain_id=chain_id, user_address=user_address
|
|
@@ -96,7 +103,7 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
96
103
|
|
|
97
104
|
async def get_market_entry(
|
|
98
105
|
self, chain_id: int, underlying: str
|
|
99
|
-
) -> tuple[bool,
|
|
106
|
+
) -> tuple[bool, MarketEntry | str]:
|
|
100
107
|
try:
|
|
101
108
|
data = await self.hyperlend_client.get_market_entry(chain_id, underlying)
|
|
102
109
|
return True, data
|
|
@@ -108,7 +115,7 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
108
115
|
chain_id: int,
|
|
109
116
|
token_address: str,
|
|
110
117
|
lookback_hours: int,
|
|
111
|
-
) -> tuple[bool,
|
|
118
|
+
) -> tuple[bool, LendRateHistory | str]:
|
|
112
119
|
try:
|
|
113
120
|
data = await self.hyperlend_client.get_lend_rate_history(
|
|
114
121
|
chain_id=chain_id,
|
|
@@ -127,7 +134,7 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
127
134
|
chain_id: int,
|
|
128
135
|
native: bool = False,
|
|
129
136
|
) -> tuple[bool, Any]:
|
|
130
|
-
|
|
137
|
+
strategy = self._strategy_address()
|
|
131
138
|
qty = int(qty)
|
|
132
139
|
if qty <= 0:
|
|
133
140
|
return False, "qty must be positive"
|
|
@@ -138,8 +145,8 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
138
145
|
target=self.gateway_address,
|
|
139
146
|
abi=WRAPPED_TOKEN_GATEWAY_ABI,
|
|
140
147
|
fn_name="depositETH",
|
|
141
|
-
args=[self._gateway_first_arg(underlying_token),
|
|
142
|
-
from_address=
|
|
148
|
+
args=[self._gateway_first_arg(underlying_token), strategy, 0],
|
|
149
|
+
from_address=strategy,
|
|
143
150
|
chain_id=chain_id,
|
|
144
151
|
value=qty,
|
|
145
152
|
)
|
|
@@ -147,7 +154,7 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
147
154
|
token_addr = self._checksum(underlying_token)
|
|
148
155
|
approved = await self._ensure_allowance(
|
|
149
156
|
token_address=token_addr,
|
|
150
|
-
owner=
|
|
157
|
+
owner=strategy,
|
|
151
158
|
spender=self.pool_address,
|
|
152
159
|
amount=qty,
|
|
153
160
|
chain_id=chain_id,
|
|
@@ -158,8 +165,8 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
158
165
|
target=self.pool_address,
|
|
159
166
|
abi=POOL_ABI,
|
|
160
167
|
fn_name="supply",
|
|
161
|
-
args=[token_addr, qty,
|
|
162
|
-
from_address=
|
|
168
|
+
args=[token_addr, qty, strategy, 0],
|
|
169
|
+
from_address=strategy,
|
|
163
170
|
chain_id=chain_id,
|
|
164
171
|
)
|
|
165
172
|
return await self._execute(tx)
|
|
@@ -172,7 +179,7 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
172
179
|
chain_id: int,
|
|
173
180
|
native: bool = False,
|
|
174
181
|
) -> tuple[bool, Any]:
|
|
175
|
-
|
|
182
|
+
strategy = self._strategy_address()
|
|
176
183
|
qty = int(qty)
|
|
177
184
|
if qty <= 0:
|
|
178
185
|
return False, "qty must be positive"
|
|
@@ -183,8 +190,8 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
183
190
|
target=self.gateway_address,
|
|
184
191
|
abi=WRAPPED_TOKEN_GATEWAY_ABI,
|
|
185
192
|
fn_name="withdrawETH",
|
|
186
|
-
args=[self._gateway_first_arg(underlying_token), qty,
|
|
187
|
-
from_address=
|
|
193
|
+
args=[self._gateway_first_arg(underlying_token), qty, strategy],
|
|
194
|
+
from_address=strategy,
|
|
188
195
|
chain_id=chain_id,
|
|
189
196
|
)
|
|
190
197
|
else:
|
|
@@ -193,8 +200,8 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
193
200
|
target=self.pool_address,
|
|
194
201
|
abi=POOL_ABI,
|
|
195
202
|
fn_name="withdraw",
|
|
196
|
-
args=[token_addr, qty,
|
|
197
|
-
from_address=
|
|
203
|
+
args=[token_addr, qty, strategy],
|
|
204
|
+
from_address=strategy,
|
|
198
205
|
chain_id=chain_id,
|
|
199
206
|
)
|
|
200
207
|
return await self._execute(tx)
|
|
@@ -233,14 +240,14 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
233
240
|
if self.simulation:
|
|
234
241
|
return True, {"simulation": tx}
|
|
235
242
|
return await self.web3.broadcast_transaction(
|
|
236
|
-
tx, wait_for_receipt=True, timeout=
|
|
243
|
+
tx, wait_for_receipt=True, timeout=DEFAULT_TRANSACTION_TIMEOUT
|
|
237
244
|
)
|
|
238
245
|
|
|
239
246
|
async def _broadcast_transaction(self, tx: dict[str, Any]) -> tuple[bool, Any]:
|
|
240
247
|
if getattr(settings, "DRY_RUN", False):
|
|
241
248
|
return True, {"dry_run": True, "transaction": tx}
|
|
242
249
|
return await self.web3.evm_transactions.broadcast_transaction(
|
|
243
|
-
tx, wait_for_receipt=True, timeout=
|
|
250
|
+
tx, wait_for_receipt=True, timeout=DEFAULT_TRANSACTION_TIMEOUT
|
|
244
251
|
)
|
|
245
252
|
|
|
246
253
|
def _encode_call(
|
|
@@ -273,17 +280,17 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
273
280
|
}
|
|
274
281
|
return tx
|
|
275
282
|
|
|
276
|
-
def
|
|
283
|
+
def _strategy_address(self) -> str:
|
|
277
284
|
addr = None
|
|
278
|
-
if isinstance(self.
|
|
279
|
-
addr = self.
|
|
280
|
-
(self.
|
|
285
|
+
if isinstance(self.strategy_wallet, dict):
|
|
286
|
+
addr = self.strategy_wallet.get("address") or (
|
|
287
|
+
(self.strategy_wallet.get("evm") or {}).get("address")
|
|
281
288
|
)
|
|
282
|
-
elif isinstance(self.
|
|
283
|
-
addr = self.
|
|
289
|
+
elif isinstance(self.strategy_wallet, str):
|
|
290
|
+
addr = self.strategy_wallet
|
|
284
291
|
if not addr:
|
|
285
292
|
raise ValueError(
|
|
286
|
-
"
|
|
293
|
+
"strategy_wallet address is required for HyperLend operations"
|
|
287
294
|
)
|
|
288
295
|
return to_checksum_address(addr)
|
|
289
296
|
|