wayfinder-paths 0.1.3__py3-none-any.whl → 0.1.5__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 +37 -32
- wayfinder_paths/__init__.py +3 -3
- wayfinder_paths/{vaults/adapters → adapters}/balance_adapter/README.md +12 -12
- wayfinder_paths/{vaults/adapters → adapters}/balance_adapter/adapter.py +12 -11
- wayfinder_paths/{vaults/adapters → adapters}/balance_adapter/examples.json +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/balance_adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/balance_adapter/test_adapter.py +12 -6
- wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/README.md +2 -2
- wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/adapter.py +30 -23
- wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/test_adapter.py +2 -2
- wayfinder_paths/adapters/hyperlend_adapter/__init__.py +7 -0
- wayfinder_paths/{vaults/adapters → adapters}/hyperlend_adapter/adapter.py +33 -26
- wayfinder_paths/{vaults/adapters → adapters}/hyperlend_adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/hyperlend_adapter/test_adapter.py +2 -2
- wayfinder_paths/{vaults/adapters → adapters}/ledger_adapter/README.md +27 -40
- wayfinder_paths/{vaults/adapters → adapters}/ledger_adapter/adapter.py +78 -75
- wayfinder_paths/{vaults/adapters → adapters}/ledger_adapter/examples.json +10 -4
- wayfinder_paths/adapters/ledger_adapter/manifest.yaml +11 -0
- wayfinder_paths/{vaults/adapters → adapters}/ledger_adapter/test_adapter.py +33 -28
- wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/README.md +2 -14
- wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/adapter.py +12 -19
- wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/test_adapter.py +2 -2
- wayfinder_paths/{vaults/adapters → adapters}/token_adapter/README.md +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/token_adapter/adapter.py +8 -4
- wayfinder_paths/adapters/token_adapter/examples.json +26 -0
- wayfinder_paths/{vaults/adapters → adapters}/token_adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/token_adapter/test_adapter.py +1 -1
- wayfinder_paths/config.example.json +3 -1
- wayfinder_paths/core/__init__.py +3 -3
- 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/engine/manifest.py +1 -1
- 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 +123 -37
- 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/{vaults/policies → policies}/enso.py +1 -1
- wayfinder_paths/{vaults/policies → policies}/hyper_evm.py +2 -2
- wayfinder_paths/{vaults/policies → policies}/hyperlend.py +1 -1
- wayfinder_paths/{vaults/policies → policies}/moonwell.py +1 -1
- wayfinder_paths/{vaults/policies → policies}/prjx.py +1 -1
- wayfinder_paths/run_strategy.py +29 -27
- wayfinder_paths/scripts/create_strategy.py +3 -3
- wayfinder_paths/scripts/make_wallets.py +6 -6
- wayfinder_paths/scripts/validate_manifests.py +2 -2
- wayfinder_paths/{vaults/strategies → strategies}/hyperlend_stable_yield_strategy/README.md +10 -9
- wayfinder_paths/{vaults/strategies → strategies}/hyperlend_stable_yield_strategy/manifest.yaml +1 -1
- wayfinder_paths/{vaults/strategies → strategies}/hyperlend_stable_yield_strategy/strategy.py +47 -167
- wayfinder_paths/{vaults/strategies → strategies}/hyperlend_stable_yield_strategy/test_strategy.py +10 -8
- wayfinder_paths/{vaults/strategies → strategies}/stablecoin_yield_strategy/README.md +15 -14
- wayfinder_paths/{vaults/strategies → strategies}/stablecoin_yield_strategy/manifest.yaml +2 -2
- wayfinder_paths/{vaults/strategies → strategies}/stablecoin_yield_strategy/strategy.py +97 -97
- wayfinder_paths/{vaults/strategies → strategies}/stablecoin_yield_strategy/test_strategy.py +8 -8
- wayfinder_paths/{vaults/templates → templates}/adapter/README.md +5 -5
- wayfinder_paths/{vaults/templates → templates}/adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/templates → templates}/adapter/test_adapter.py +1 -1
- wayfinder_paths/{vaults/templates → templates}/strategy/README.md +10 -9
- wayfinder_paths/{vaults/templates → templates}/strategy/manifest.yaml +1 -1
- wayfinder_paths/{vaults/templates → templates}/strategy/test_strategy.py +8 -8
- wayfinder_paths/tests/test_test_coverage.py +5 -5
- {wayfinder_paths-0.1.3.dist-info → wayfinder_paths-0.1.5.dist-info}/METADATA +146 -69
- wayfinder_paths-0.1.5.dist-info/RECORD +126 -0
- wayfinder_paths/vaults/adapters/hyperlend_adapter/__init__.py +0 -7
- wayfinder_paths/vaults/adapters/ledger_adapter/manifest.yaml +0 -11
- wayfinder_paths/vaults/adapters/token_adapter/examples.json +0 -26
- wayfinder_paths/vaults/strategies/__init__.py +0 -0
- wayfinder_paths-0.1.3.dist-info/RECORD +0 -126
- /wayfinder_paths/{vaults → adapters}/__init__.py +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/__init__.py +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/examples.json +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/ledger_adapter/__init__.py +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/__init__.py +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/examples.json +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/token_adapter/__init__.py +0 -0
- /wayfinder_paths/{vaults/policies → policies}/erc20.py +0 -0
- /wayfinder_paths/{vaults/policies → policies}/evm.py +0 -0
- /wayfinder_paths/{vaults/policies → policies}/hyperliquid.py +0 -0
- /wayfinder_paths/{vaults/policies → policies}/util.py +0 -0
- /wayfinder_paths/{vaults/adapters → strategies}/__init__.py +0 -0
- /wayfinder_paths/{vaults/strategies → strategies}/config.py +0 -0
- /wayfinder_paths/{vaults/strategies → strategies}/hyperlend_stable_yield_strategy/examples.json +0 -0
- /wayfinder_paths/{vaults/strategies → strategies}/stablecoin_yield_strategy/examples.json +0 -0
- /wayfinder_paths/{vaults/templates → templates}/adapter/adapter.py +0 -0
- /wayfinder_paths/{vaults/templates → templates}/adapter/examples.json +0 -0
- /wayfinder_paths/{vaults/templates → templates}/strategy/examples.json +0 -0
- /wayfinder_paths/{vaults/templates → templates}/strategy/strategy.py +0 -0
- {wayfinder_paths-0.1.3.dist-info → wayfinder_paths-0.1.5.dist-info}/LICENSE +0 -0
- {wayfinder_paths-0.1.3.dist-info → wayfinder_paths-0.1.5.dist-info}/WHEEL +0 -0
|
@@ -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
|
|
|
@@ -2,7 +2,7 @@ from unittest.mock import AsyncMock, patch
|
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
|
-
from wayfinder_paths.
|
|
5
|
+
from wayfinder_paths.adapters.hyperlend_adapter.adapter import HyperlendAdapter
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class TestHyperlendAdapter:
|
|
@@ -18,7 +18,7 @@ class TestHyperlendAdapter:
|
|
|
18
18
|
def adapter(self, mock_hyperlend_client):
|
|
19
19
|
"""Create a HyperlendAdapter instance with mocked client for testing"""
|
|
20
20
|
with patch(
|
|
21
|
-
"wayfinder_paths.
|
|
21
|
+
"wayfinder_paths.adapters.hyperlend_adapter.adapter.HyperlendClient",
|
|
22
22
|
return_value=mock_hyperlend_client,
|
|
23
23
|
):
|
|
24
24
|
return HyperlendAdapter()
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Ledger Adapter
|
|
2
2
|
|
|
3
|
-
A Wayfinder adapter that provides high-level operations for
|
|
3
|
+
A Wayfinder adapter that provides high-level operations for strategy transaction history and bookkeeping. This adapter wraps the `LedgerClient` to offer strategy-friendly methods for recording and retrieving strategy operations.
|
|
4
4
|
|
|
5
5
|
## Capabilities
|
|
6
6
|
|
|
7
|
-
- `ledger.read`: Read
|
|
7
|
+
- `ledger.read`: Read strategy transaction data and net deposits
|
|
8
8
|
- `ledger.write`: Record deposits, withdrawals, and operations
|
|
9
|
-
- `
|
|
10
|
-
- `
|
|
11
|
-
- `
|
|
12
|
-
- `
|
|
9
|
+
- `strategy.transactions`: Access strategy transaction history
|
|
10
|
+
- `strategy.deposits`: Record deposit transactions
|
|
11
|
+
- `strategy.withdrawals`: Record withdrawal transactions
|
|
12
|
+
- `strategy.operations`: Record strategy operations (swaps, rebalances, etc.)
|
|
13
13
|
|
|
14
14
|
## Configuration
|
|
15
15
|
|
|
@@ -25,16 +25,16 @@ The LedgerClient will automatically:
|
|
|
25
25
|
### Initialize the Adapter
|
|
26
26
|
|
|
27
27
|
```python
|
|
28
|
-
from wayfinder_paths.
|
|
28
|
+
from wayfinder_paths.adapters.ledger_adapter.adapter import LedgerAdapter
|
|
29
29
|
|
|
30
30
|
# No configuration needed - uses LedgerClient with automatic settings
|
|
31
31
|
adapter = LedgerAdapter()
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
### Get
|
|
34
|
+
### Get Strategy Transaction History
|
|
35
35
|
|
|
36
36
|
```python
|
|
37
|
-
success, data = await adapter.
|
|
37
|
+
success, data = await adapter.get_strategy_transactions(
|
|
38
38
|
wallet_address="0x1234567890123456789012345678901234567890",
|
|
39
39
|
limit=10,
|
|
40
40
|
offset=0
|
|
@@ -49,7 +49,7 @@ else:
|
|
|
49
49
|
### Get Net Deposit Amount
|
|
50
50
|
|
|
51
51
|
```python
|
|
52
|
-
success, data = await adapter.
|
|
52
|
+
success, data = await adapter.get_strategy_net_deposit(
|
|
53
53
|
wallet_address="0x1234567890123456789012345678901234567890"
|
|
54
54
|
)
|
|
55
55
|
if success:
|
|
@@ -93,51 +93,38 @@ else:
|
|
|
93
93
|
print(f"Error: {data}")
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
### Record an Operation
|
|
96
|
+
### Record an Operation
|
|
97
97
|
|
|
98
98
|
```python
|
|
99
|
+
from wayfinder_paths.adapters.ledger_adapter.models import SWAP
|
|
100
|
+
|
|
101
|
+
operation = SWAP(
|
|
102
|
+
from_token_id="0xA0b86...",
|
|
103
|
+
to_token_id="0xB1c97...",
|
|
104
|
+
from_amount="1000000000000000000",
|
|
105
|
+
to_amount="995000000000000000",
|
|
106
|
+
from_amount_usd=1000.0,
|
|
107
|
+
to_amount_usd=995.0,
|
|
108
|
+
)
|
|
109
|
+
|
|
99
110
|
success, op = await adapter.record_operation(
|
|
100
|
-
wallet_address=
|
|
101
|
-
operation_data=
|
|
102
|
-
"type": "SWAP",
|
|
103
|
-
"from_token": "...",
|
|
104
|
-
"to_token": "...",
|
|
105
|
-
"amount_in": "1000000000000000000",
|
|
106
|
-
"amount_out": "995000000000000000",
|
|
107
|
-
},
|
|
111
|
+
wallet_address=strategy_address,
|
|
112
|
+
operation_data=operation,
|
|
108
113
|
usd_value="1000.00",
|
|
109
114
|
strategy_name="StablecoinYieldStrategy",
|
|
110
115
|
)
|
|
111
116
|
|
|
112
|
-
success, cashflow = await adapter.record_cashflow(
|
|
113
|
-
wallet_address=vault_address,
|
|
114
|
-
block_timestamp=int(time.time()),
|
|
115
|
-
token_addr="0x...",
|
|
116
|
-
amount="250000000000000000",
|
|
117
|
-
description="reward",
|
|
118
|
-
strategy_name="StablecoinYieldStrategy",
|
|
119
|
-
)
|
|
120
117
|
```
|
|
121
118
|
|
|
122
119
|
### Latest Transactions and Summaries
|
|
123
120
|
|
|
124
121
|
```python
|
|
125
|
-
success, latest = await adapter.
|
|
126
|
-
success, summary = await adapter.get_transaction_summary(wallet_address=
|
|
122
|
+
success, latest = await adapter.get_strategy_latest_transactions(wallet_address=strategy_address)
|
|
123
|
+
success, summary = await adapter.get_transaction_summary(wallet_address=strategy_address, limit=5)
|
|
127
124
|
if success:
|
|
128
125
|
print(f"Total transactions: {summary.get('total_transactions')}")
|
|
129
126
|
```
|
|
130
127
|
|
|
131
|
-
## API Endpoints
|
|
132
|
-
|
|
133
|
-
The adapter uses the following Wayfinder API endpoints:
|
|
134
|
-
|
|
135
|
-
- `GET /api/v1/public/vaults/transactions/` - Get vault transactions
|
|
136
|
-
- `GET /api/v1/public/vaults/net-deposit/` - Get net deposit amount
|
|
137
|
-
- `POST /api/v1/public/vaults/deposits/` - Record a deposit
|
|
138
|
-
- `POST /api/v1/public/vaults/withdrawals/` - Record a withdrawal
|
|
139
|
-
- `POST /api/v1/public/vaults/operations/` - Record an operation
|
|
140
|
-
|
|
141
128
|
## Error Handling
|
|
142
129
|
|
|
143
130
|
All methods return a tuple of `(success: bool, data: Any)` where:
|
|
@@ -149,7 +136,7 @@ All methods return a tuple of `(success: bool, data: Any)` where:
|
|
|
149
136
|
Run the adapter tests:
|
|
150
137
|
|
|
151
138
|
```bash
|
|
152
|
-
pytest wayfinder_paths/
|
|
139
|
+
pytest wayfinder_paths/adapters/ledger_adapter/test_adapter.py -v
|
|
153
140
|
```
|
|
154
141
|
|
|
155
142
|
## Dependencies
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
3
|
from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
|
|
4
|
-
from wayfinder_paths.core.
|
|
4
|
+
from wayfinder_paths.core.adapters.models import Operation
|
|
5
|
+
from wayfinder_paths.core.clients.LedgerClient import (
|
|
6
|
+
LedgerClient,
|
|
7
|
+
NetDeposit,
|
|
8
|
+
StrategyTransactionList,
|
|
9
|
+
TransactionRecord,
|
|
10
|
+
)
|
|
11
|
+
from wayfinder_paths.core.strategies.Strategy import StatusDict
|
|
5
12
|
|
|
6
13
|
|
|
7
14
|
class LedgerAdapter(BaseAdapter):
|
|
8
15
|
"""
|
|
9
|
-
Ledger adapter for
|
|
16
|
+
Ledger adapter for strategy transaction history and bookkeeping operations.
|
|
10
17
|
|
|
11
18
|
Provides high-level operations for:
|
|
12
|
-
- Fetching
|
|
19
|
+
- Fetching strategy transaction history
|
|
13
20
|
- Getting net deposit amounts
|
|
14
21
|
- Getting last rotation time
|
|
15
|
-
- Recording deposits, withdrawals,
|
|
22
|
+
- Recording deposits, withdrawals, and operations
|
|
16
23
|
"""
|
|
17
24
|
|
|
18
25
|
adapter_type: str = "LEDGER"
|
|
@@ -25,14 +32,14 @@ class LedgerAdapter(BaseAdapter):
|
|
|
25
32
|
super().__init__("ledger_adapter", config)
|
|
26
33
|
self.ledger_client = ledger_client or LedgerClient()
|
|
27
34
|
|
|
28
|
-
async def
|
|
35
|
+
async def get_strategy_transactions(
|
|
29
36
|
self, wallet_address: str, limit: int = 50, offset: int = 0
|
|
30
|
-
) -> tuple[bool,
|
|
37
|
+
) -> tuple[bool, StrategyTransactionList | str]:
|
|
31
38
|
"""
|
|
32
|
-
Get paginated
|
|
39
|
+
Get paginated strategy transaction history.
|
|
33
40
|
|
|
34
41
|
Args:
|
|
35
|
-
wallet_address:
|
|
42
|
+
wallet_address: Strategy wallet address
|
|
36
43
|
limit: Maximum number of transactions to return
|
|
37
44
|
offset: Number of transactions to skip
|
|
38
45
|
|
|
@@ -40,52 +47,54 @@ class LedgerAdapter(BaseAdapter):
|
|
|
40
47
|
Tuple of (success, data) where data is transaction list or error message
|
|
41
48
|
"""
|
|
42
49
|
try:
|
|
43
|
-
data = await self.ledger_client.
|
|
50
|
+
data = await self.ledger_client.get_strategy_transactions(
|
|
44
51
|
wallet_address=wallet_address, limit=limit, offset=offset
|
|
45
52
|
)
|
|
46
53
|
return (True, data)
|
|
47
54
|
except Exception as e:
|
|
48
|
-
self.logger.error(f"Error fetching
|
|
55
|
+
self.logger.error(f"Error fetching strategy transactions: {e}")
|
|
49
56
|
return (False, str(e))
|
|
50
57
|
|
|
51
|
-
async def
|
|
58
|
+
async def get_strategy_net_deposit(
|
|
59
|
+
self, wallet_address: str
|
|
60
|
+
) -> tuple[bool, NetDeposit | str]:
|
|
52
61
|
"""
|
|
53
|
-
Get net deposit amount (deposits - withdrawals) for a
|
|
62
|
+
Get net deposit amount (deposits - withdrawals) for a strategy.
|
|
54
63
|
|
|
55
64
|
Args:
|
|
56
|
-
wallet_address:
|
|
65
|
+
wallet_address: Strategy wallet address
|
|
57
66
|
|
|
58
67
|
Returns:
|
|
59
68
|
Tuple of (success, data) where data contains net_deposit or error message
|
|
60
69
|
"""
|
|
61
70
|
try:
|
|
62
|
-
data = await self.ledger_client.
|
|
71
|
+
data = await self.ledger_client.get_strategy_net_deposit(
|
|
63
72
|
wallet_address=wallet_address
|
|
64
73
|
)
|
|
65
74
|
return (True, data)
|
|
66
75
|
except Exception as e:
|
|
67
|
-
self.logger.error(f"Error fetching
|
|
76
|
+
self.logger.error(f"Error fetching strategy net deposit: {e}")
|
|
68
77
|
return (False, str(e))
|
|
69
78
|
|
|
70
|
-
async def
|
|
79
|
+
async def get_strategy_latest_transactions(
|
|
71
80
|
self, wallet_address: str
|
|
72
|
-
) -> tuple[bool,
|
|
81
|
+
) -> tuple[bool, StrategyTransactionList | str]:
|
|
73
82
|
"""
|
|
74
|
-
Get the latest transactions for a
|
|
83
|
+
Get the latest transactions for a strategy.
|
|
75
84
|
|
|
76
85
|
Args:
|
|
77
|
-
wallet_address:
|
|
86
|
+
wallet_address: Strategy wallet address
|
|
78
87
|
|
|
79
88
|
Returns:
|
|
80
89
|
Tuple of (success, data) where data contains latest transactions or error message
|
|
81
90
|
"""
|
|
82
91
|
try:
|
|
83
|
-
data = await self.ledger_client.
|
|
92
|
+
data = await self.ledger_client.get_strategy_latest_transactions(
|
|
84
93
|
wallet_address=wallet_address
|
|
85
94
|
)
|
|
86
95
|
return (True, data)
|
|
87
96
|
except Exception as e:
|
|
88
|
-
self.logger.error(f"Error fetching
|
|
97
|
+
self.logger.error(f"Error fetching strategy last transactions: {e}")
|
|
89
98
|
return (False, str(e))
|
|
90
99
|
|
|
91
100
|
async def record_deposit(
|
|
@@ -97,12 +106,12 @@ class LedgerAdapter(BaseAdapter):
|
|
|
97
106
|
usd_value: str | float,
|
|
98
107
|
data: dict[str, Any] | None = None,
|
|
99
108
|
strategy_name: str | None = None,
|
|
100
|
-
) -> tuple[bool,
|
|
109
|
+
) -> tuple[bool, TransactionRecord | str]:
|
|
101
110
|
"""
|
|
102
|
-
Record a
|
|
111
|
+
Record a strategy deposit transaction.
|
|
103
112
|
|
|
104
113
|
Args:
|
|
105
|
-
wallet_address:
|
|
114
|
+
wallet_address: Strategy wallet address
|
|
106
115
|
chain_id: Blockchain chain ID
|
|
107
116
|
token_address: Token contract address
|
|
108
117
|
token_amount: Amount deposited (in token units)
|
|
@@ -114,7 +123,7 @@ class LedgerAdapter(BaseAdapter):
|
|
|
114
123
|
Tuple of (success, data) where data is transaction record or error message
|
|
115
124
|
"""
|
|
116
125
|
try:
|
|
117
|
-
result = await self.ledger_client.
|
|
126
|
+
result = await self.ledger_client.add_strategy_deposit(
|
|
118
127
|
wallet_address=wallet_address,
|
|
119
128
|
chain_id=chain_id,
|
|
120
129
|
token_address=token_address,
|
|
@@ -137,12 +146,12 @@ class LedgerAdapter(BaseAdapter):
|
|
|
137
146
|
usd_value: str | float,
|
|
138
147
|
data: dict[str, Any] | None = None,
|
|
139
148
|
strategy_name: str | None = None,
|
|
140
|
-
) -> tuple[bool,
|
|
149
|
+
) -> tuple[bool, TransactionRecord | str]:
|
|
141
150
|
"""
|
|
142
|
-
Record a
|
|
151
|
+
Record a strategy withdrawal transaction.
|
|
143
152
|
|
|
144
153
|
Args:
|
|
145
|
-
wallet_address:
|
|
154
|
+
wallet_address: Strategy wallet address
|
|
146
155
|
chain_id: Blockchain chain ID
|
|
147
156
|
token_address: Token contract address
|
|
148
157
|
token_amount: Amount withdrawn (in token units)
|
|
@@ -154,7 +163,7 @@ class LedgerAdapter(BaseAdapter):
|
|
|
154
163
|
Tuple of (success, data) where data is transaction record or error message
|
|
155
164
|
"""
|
|
156
165
|
try:
|
|
157
|
-
result = await self.ledger_client.
|
|
166
|
+
result = await self.ledger_client.add_strategy_withdraw(
|
|
158
167
|
wallet_address=wallet_address,
|
|
159
168
|
chain_id=chain_id,
|
|
160
169
|
token_address=token_address,
|
|
@@ -171,16 +180,16 @@ class LedgerAdapter(BaseAdapter):
|
|
|
171
180
|
async def record_operation(
|
|
172
181
|
self,
|
|
173
182
|
wallet_address: str,
|
|
174
|
-
operation_data:
|
|
183
|
+
operation_data: Operation,
|
|
175
184
|
usd_value: str | float,
|
|
176
185
|
strategy_name: str | None = None,
|
|
177
|
-
) -> tuple[bool,
|
|
186
|
+
) -> tuple[bool, TransactionRecord | str]:
|
|
178
187
|
"""
|
|
179
|
-
Record a
|
|
188
|
+
Record a strategy operation (e.g., swaps, rebalances) for bookkeeping.
|
|
180
189
|
|
|
181
190
|
Args:
|
|
182
|
-
wallet_address:
|
|
183
|
-
operation_data:
|
|
191
|
+
wallet_address: Strategy wallet address
|
|
192
|
+
operation_data: Operation model (SWAP, LEND, BORROW, etc.)
|
|
184
193
|
usd_value: USD value of the operation
|
|
185
194
|
strategy_name: Name of the strategy performing the operation
|
|
186
195
|
|
|
@@ -188,7 +197,7 @@ class LedgerAdapter(BaseAdapter):
|
|
|
188
197
|
Tuple of (success, data) where data is operation record or error message
|
|
189
198
|
"""
|
|
190
199
|
try:
|
|
191
|
-
result = await self.ledger_client.
|
|
200
|
+
result = await self.ledger_client.add_strategy_operation(
|
|
192
201
|
wallet_address=wallet_address,
|
|
193
202
|
operation_data=operation_data,
|
|
194
203
|
usd_value=usd_value,
|
|
@@ -199,58 +208,21 @@ class LedgerAdapter(BaseAdapter):
|
|
|
199
208
|
self.logger.error(f"Error recording operation: {e}")
|
|
200
209
|
return (False, str(e))
|
|
201
210
|
|
|
202
|
-
async def record_cashflow(
|
|
203
|
-
self,
|
|
204
|
-
wallet_address: str,
|
|
205
|
-
block_timestamp: int,
|
|
206
|
-
token_addr: str,
|
|
207
|
-
amount: str | int | float,
|
|
208
|
-
description: str,
|
|
209
|
-
strategy_name: str | None = None,
|
|
210
|
-
) -> tuple[bool, Any]:
|
|
211
|
-
"""
|
|
212
|
-
Record a vault cashflow (interest, funding, reward, or fee).
|
|
213
|
-
|
|
214
|
-
Args:
|
|
215
|
-
wallet_address: Vault wallet address
|
|
216
|
-
block_timestamp: Block timestamp (Unix timestamp)
|
|
217
|
-
token_addr: Token contract address
|
|
218
|
-
amount: Cashflow amount (in token units)
|
|
219
|
-
description: Cashflow type - must be one of: "interest", "funding", "reward", "fee"
|
|
220
|
-
strategy_name: Optional strategy name
|
|
221
|
-
|
|
222
|
-
Returns:
|
|
223
|
-
Tuple of (success, data) where data is cashflow record or error message
|
|
224
|
-
"""
|
|
225
|
-
try:
|
|
226
|
-
result = await self.ledger_client.add_vault_cashflow(
|
|
227
|
-
wallet_address=wallet_address,
|
|
228
|
-
block_timestamp=block_timestamp,
|
|
229
|
-
token_addr=token_addr,
|
|
230
|
-
amount=amount,
|
|
231
|
-
description=description,
|
|
232
|
-
strategy_name=strategy_name,
|
|
233
|
-
)
|
|
234
|
-
return (True, result)
|
|
235
|
-
except Exception as e:
|
|
236
|
-
self.logger.error(f"Error recording cashflow: {e}")
|
|
237
|
-
return (False, str(e))
|
|
238
|
-
|
|
239
211
|
async def get_transaction_summary(
|
|
240
212
|
self, wallet_address: str, limit: int = 10
|
|
241
213
|
) -> tuple[bool, Any]:
|
|
242
214
|
"""
|
|
243
|
-
Get a summary of recent
|
|
215
|
+
Get a summary of recent strategy transactions.
|
|
244
216
|
|
|
245
217
|
Args:
|
|
246
|
-
wallet_address:
|
|
218
|
+
wallet_address: Strategy wallet address
|
|
247
219
|
limit: Number of recent transactions to include
|
|
248
220
|
|
|
249
221
|
Returns:
|
|
250
222
|
Tuple of (success, data) where data is transaction summary or error message
|
|
251
223
|
"""
|
|
252
224
|
try:
|
|
253
|
-
success, transactions_data = await self.
|
|
225
|
+
success, transactions_data = await self.get_strategy_transactions(
|
|
254
226
|
wallet_address=wallet_address, limit=limit
|
|
255
227
|
)
|
|
256
228
|
|
|
@@ -284,3 +256,34 @@ class LedgerAdapter(BaseAdapter):
|
|
|
284
256
|
except Exception as e:
|
|
285
257
|
self.logger.error(f"Error creating transaction summary: {e}")
|
|
286
258
|
return (False, str(e))
|
|
259
|
+
|
|
260
|
+
async def record_strategy_snapshot(
|
|
261
|
+
self, wallet_address: str, strategy_status: StatusDict
|
|
262
|
+
) -> tuple[bool, None | str]:
|
|
263
|
+
"""
|
|
264
|
+
Record a strategy snapshot with current state.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
wallet_address: Strategy wallet address
|
|
268
|
+
strat_portfolio_value: Current portfolio value
|
|
269
|
+
net_deposit: Net deposit amount
|
|
270
|
+
strategy_status: Current strategy status dictionary
|
|
271
|
+
gas_available: Available gas amount
|
|
272
|
+
gassed_up: Whether the strategy is gassed up
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
Tuple of (success, None) on success or (False, error_message) on failure
|
|
276
|
+
"""
|
|
277
|
+
try:
|
|
278
|
+
await self.ledger_client.strategy_snapshot(
|
|
279
|
+
wallet_address=wallet_address,
|
|
280
|
+
strat_portfolio_value=strategy_status["portfolio_value"],
|
|
281
|
+
net_deposit=strategy_status["net_deposit"],
|
|
282
|
+
strategy_status=strategy_status["strategy_status"],
|
|
283
|
+
gas_available=strategy_status["gas_available"],
|
|
284
|
+
gassed_up=strategy_status["gassed_up"],
|
|
285
|
+
)
|
|
286
|
+
return (True, None)
|
|
287
|
+
except Exception as e:
|
|
288
|
+
self.logger.error(f"Error recording strategy snapshot: {e}")
|
|
289
|
+
return (False, str(e))
|
|
@@ -80,14 +80,20 @@
|
|
|
80
80
|
},
|
|
81
81
|
"record_operation": {
|
|
82
82
|
"description": "Record a vault operation (swap, rebalance, etc.)",
|
|
83
|
+
"note": "operation_data must be a Pydantic Operation model (currently only SWAP is implemented)",
|
|
83
84
|
"input": {
|
|
84
85
|
"wallet_address": "0x1234567890123456789012345678901234567890",
|
|
85
86
|
"operation_data": {
|
|
86
87
|
"type": "SWAP",
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
88
|
+
"from_token_id": "0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
|
|
89
|
+
"to_token_id": "0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
|
|
90
|
+
"from_amount": "1000000000000000000",
|
|
91
|
+
"to_amount": "995000000000000000",
|
|
92
|
+
"from_amount_usd": 1000.0,
|
|
93
|
+
"to_amount_usd": 995.0,
|
|
94
|
+
"transaction_hash": "0xabcdef...",
|
|
95
|
+
"transaction_status": "success",
|
|
96
|
+
"transaction_receipt": null
|
|
91
97
|
},
|
|
92
98
|
"usd_value": "1000.00",
|
|
93
99
|
"strategy_name": "StablecoinYieldStrategy"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
schema_version: "0.1"
|
|
2
|
+
entrypoint: "adapters.ledger_adapter.adapter.LedgerAdapter"
|
|
3
|
+
capabilities:
|
|
4
|
+
- "ledger.read"
|
|
5
|
+
- "ledger.write"
|
|
6
|
+
- "strategy.transactions"
|
|
7
|
+
- "strategy.deposits"
|
|
8
|
+
- "strategy.withdrawals"
|
|
9
|
+
- "strategy.operations"
|
|
10
|
+
dependencies:
|
|
11
|
+
- "LedgerClient"
|