wayfinder-paths 0.1.22__py3-none-any.whl → 0.1.23__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/__init__.py +0 -4
- wayfinder_paths/adapters/balance_adapter/README.md +0 -1
- wayfinder_paths/adapters/balance_adapter/adapter.py +65 -169
- wayfinder_paths/adapters/balance_adapter/test_adapter.py +41 -113
- wayfinder_paths/adapters/brap_adapter/README.md +22 -75
- wayfinder_paths/adapters/brap_adapter/adapter.py +187 -576
- wayfinder_paths/adapters/brap_adapter/examples.json +21 -140
- wayfinder_paths/adapters/brap_adapter/test_adapter.py +6 -234
- wayfinder_paths/adapters/hyperlend_adapter/adapter.py +39 -86
- wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +5 -1
- wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +6 -5
- wayfinder_paths/adapters/ledger_adapter/README.md +4 -1
- wayfinder_paths/adapters/ledger_adapter/adapter.py +3 -3
- wayfinder_paths/adapters/moonwell_adapter/adapter.py +108 -198
- wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +37 -23
- wayfinder_paths/adapters/token_adapter/adapter.py +14 -0
- wayfinder_paths/core/__init__.py +0 -3
- wayfinder_paths/core/clients/BRAPClient.py +3 -0
- wayfinder_paths/core/clients/ClientManager.py +0 -7
- wayfinder_paths/core/clients/LedgerClient.py +196 -172
- wayfinder_paths/core/clients/WayfinderClient.py +0 -1
- wayfinder_paths/core/clients/__init__.py +0 -5
- wayfinder_paths/core/clients/protocols.py +0 -13
- wayfinder_paths/core/config.py +0 -164
- wayfinder_paths/core/constants/__init__.py +58 -2
- wayfinder_paths/core/constants/base.py +8 -22
- wayfinder_paths/core/constants/chains.py +36 -0
- wayfinder_paths/core/constants/contracts.py +39 -0
- wayfinder_paths/core/constants/tokens.py +9 -0
- wayfinder_paths/core/strategies/Strategy.py +0 -10
- wayfinder_paths/core/utils/evm_helpers.py +5 -15
- wayfinder_paths/core/utils/tokens.py +28 -0
- wayfinder_paths/core/utils/transaction.py +13 -7
- wayfinder_paths/core/utils/web3.py +5 -3
- wayfinder_paths/policies/enso.py +1 -2
- wayfinder_paths/policies/hyper_evm.py +6 -3
- wayfinder_paths/policies/hyperlend.py +1 -2
- wayfinder_paths/policies/moonwell.py +12 -7
- wayfinder_paths/policies/prjx.py +1 -3
- wayfinder_paths/run_strategy.py +97 -300
- wayfinder_paths/strategies/basis_trading_strategy/constants.py +3 -1
- wayfinder_paths/strategies/basis_trading_strategy/strategy.py +19 -14
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +12 -11
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +20 -33
- wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +21 -18
- wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +69 -130
- wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +32 -42
- {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/METADATA +2 -3
- {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/RECORD +51 -60
- {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/WHEEL +1 -1
- wayfinder_paths/core/clients/WalletClient.py +0 -41
- wayfinder_paths/core/engine/StrategyJob.py +0 -110
- wayfinder_paths/core/services/test_local_evm_txn.py +0 -145
- wayfinder_paths/templates/adapter/README.md +0 -150
- wayfinder_paths/templates/adapter/adapter.py +0 -16
- wayfinder_paths/templates/adapter/examples.json +0 -8
- wayfinder_paths/templates/adapter/test_adapter.py +0 -30
- wayfinder_paths/templates/strategy/README.md +0 -186
- wayfinder_paths/templates/strategy/examples.json +0 -11
- wayfinder_paths/templates/strategy/strategy.py +0 -35
- wayfinder_paths/templates/strategy/test_strategy.py +0 -166
- wayfinder_paths/tests/test_smoke_manifest.py +0 -63
- {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/LICENSE +0 -0
|
@@ -12,23 +12,19 @@ from wayfinder_paths.core.clients.HyperlendClient import (
|
|
|
12
12
|
MarketEntry,
|
|
13
13
|
StableMarketsHeadroomResponse,
|
|
14
14
|
)
|
|
15
|
+
from wayfinder_paths.core.constants.contracts import (
|
|
16
|
+
HYPEREVM_WHYPE,
|
|
17
|
+
HYPERLEND_POOL,
|
|
18
|
+
HYPERLEND_WRAPPED_TOKEN_GATEWAY,
|
|
19
|
+
)
|
|
15
20
|
from wayfinder_paths.core.constants.hyperlend_abi import (
|
|
16
21
|
POOL_ABI,
|
|
17
22
|
WRAPPED_TOKEN_GATEWAY_ABI,
|
|
18
23
|
)
|
|
19
|
-
from wayfinder_paths.core.utils.tokens import
|
|
20
|
-
build_approve_transaction,
|
|
21
|
-
get_token_allowance,
|
|
22
|
-
)
|
|
24
|
+
from wayfinder_paths.core.utils.tokens import ensure_allowance
|
|
23
25
|
from wayfinder_paths.core.utils.transaction import send_transaction
|
|
24
26
|
from wayfinder_paths.core.utils.web3 import web3_from_chain_id
|
|
25
27
|
|
|
26
|
-
HYPERLEND_DEFAULTS = {
|
|
27
|
-
"pool": "0x00A89d7a5A02160f20150EbEA7a2b5E4879A1A8b",
|
|
28
|
-
"wrapped_token_gateway": "0x49558c794ea2aC8974C9F27886DDfAa951E99171",
|
|
29
|
-
"wrapped_native_underlying": "0x5555555555555555555555555555555555555555",
|
|
30
|
-
}
|
|
31
|
-
|
|
32
28
|
|
|
33
29
|
class HyperlendAdapter(BaseAdapter):
|
|
34
30
|
adapter_type = "HYPERLEND"
|
|
@@ -39,32 +35,30 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
39
35
|
strategy_wallet_signing_callback=None,
|
|
40
36
|
) -> None:
|
|
41
37
|
super().__init__("hyperlend_adapter", config)
|
|
42
|
-
|
|
43
|
-
adapter_cfg =
|
|
38
|
+
config = config or {}
|
|
39
|
+
adapter_cfg = config.get("hyperlend_adapter") or {}
|
|
44
40
|
|
|
45
41
|
self.strategy_wallet_signing_callback = strategy_wallet_signing_callback
|
|
46
42
|
self.hyperlend_client = HyperlendClient()
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
strategy_wallet = config.get("strategy_wallet") or {}
|
|
45
|
+
strategy_addr = strategy_wallet.get("address")
|
|
46
|
+
if not strategy_addr:
|
|
47
|
+
raise ValueError("strategy_wallet.address is required")
|
|
48
|
+
self.strategy_wallet_address = to_checksum_address(strategy_addr)
|
|
49
|
+
self.pool_address = to_checksum_address(
|
|
50
|
+
adapter_cfg.get("pool_address") or HYPERLEND_POOL
|
|
51
51
|
)
|
|
52
|
-
self.gateway_address =
|
|
53
|
-
adapter_cfg.get("wrapped_token_gateway")
|
|
54
|
-
or HYPERLEND_DEFAULTS["wrapped_token_gateway"]
|
|
52
|
+
self.gateway_address = to_checksum_address(
|
|
53
|
+
adapter_cfg.get("wrapped_token_gateway") or HYPERLEND_WRAPPED_TOKEN_GATEWAY
|
|
55
54
|
)
|
|
56
|
-
self.wrapped_native =
|
|
57
|
-
adapter_cfg.get("wrapped_native_underlying")
|
|
58
|
-
or HYPERLEND_DEFAULTS["wrapped_native_underlying"]
|
|
55
|
+
self.wrapped_native = to_checksum_address(
|
|
56
|
+
adapter_cfg.get("wrapped_native_underlying") or HYPEREVM_WHYPE
|
|
59
57
|
)
|
|
60
58
|
self.gateway_deposit_takes_pool = adapter_cfg.get(
|
|
61
59
|
"gateway_deposit_takes_pool", True
|
|
62
60
|
)
|
|
63
61
|
|
|
64
|
-
# ------------------------------------------------------------------ #
|
|
65
|
-
# Public API #
|
|
66
|
-
# ------------------------------------------------------------------ #
|
|
67
|
-
|
|
68
62
|
async def get_stable_markets(
|
|
69
63
|
self,
|
|
70
64
|
*,
|
|
@@ -131,14 +125,14 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
131
125
|
chain_id: int,
|
|
132
126
|
native: bool = False,
|
|
133
127
|
) -> tuple[bool, Any]:
|
|
134
|
-
strategy = self.
|
|
128
|
+
strategy = self.strategy_wallet_address
|
|
135
129
|
qty = int(qty)
|
|
136
130
|
if qty <= 0:
|
|
137
131
|
return False, "qty must be positive"
|
|
138
132
|
chain_id = int(chain_id)
|
|
139
133
|
|
|
140
134
|
if native:
|
|
141
|
-
|
|
135
|
+
transcation = await self._encode_call(
|
|
142
136
|
target=self.gateway_address,
|
|
143
137
|
abi=WRAPPED_TOKEN_GATEWAY_ABI,
|
|
144
138
|
fn_name="depositETH",
|
|
@@ -148,17 +142,18 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
148
142
|
value=qty,
|
|
149
143
|
)
|
|
150
144
|
else:
|
|
151
|
-
token_addr =
|
|
152
|
-
approved = await
|
|
145
|
+
token_addr = to_checksum_address(underlying_token)
|
|
146
|
+
approved = await ensure_allowance(
|
|
153
147
|
token_address=token_addr,
|
|
154
148
|
owner=strategy,
|
|
155
149
|
spender=self.pool_address,
|
|
156
150
|
amount=qty,
|
|
157
151
|
chain_id=chain_id,
|
|
152
|
+
signing_callback=self.strategy_wallet_signing_callback,
|
|
158
153
|
)
|
|
159
154
|
if not approved[0]:
|
|
160
155
|
return approved
|
|
161
|
-
|
|
156
|
+
transcation = await self._encode_call(
|
|
162
157
|
target=self.pool_address,
|
|
163
158
|
abi=POOL_ABI,
|
|
164
159
|
fn_name="supply",
|
|
@@ -166,7 +161,10 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
166
161
|
from_address=strategy,
|
|
167
162
|
chain_id=chain_id,
|
|
168
163
|
)
|
|
169
|
-
|
|
164
|
+
txn_hash = await send_transaction(
|
|
165
|
+
transcation, self.strategy_wallet_signing_callback
|
|
166
|
+
)
|
|
167
|
+
return True, txn_hash
|
|
170
168
|
|
|
171
169
|
async def unlend(
|
|
172
170
|
self,
|
|
@@ -176,14 +174,14 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
176
174
|
chain_id: int,
|
|
177
175
|
native: bool = False,
|
|
178
176
|
) -> tuple[bool, Any]:
|
|
179
|
-
strategy = self.
|
|
177
|
+
strategy = self.strategy_wallet_address
|
|
180
178
|
qty = int(qty)
|
|
181
179
|
if qty <= 0:
|
|
182
180
|
return False, "qty must be positive"
|
|
183
181
|
chain_id = int(chain_id)
|
|
184
182
|
|
|
185
183
|
if native:
|
|
186
|
-
|
|
184
|
+
transaction = await self._encode_call(
|
|
187
185
|
target=self.gateway_address,
|
|
188
186
|
abi=WRAPPED_TOKEN_GATEWAY_ABI,
|
|
189
187
|
fn_name="withdrawETH",
|
|
@@ -192,8 +190,8 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
192
190
|
chain_id=chain_id,
|
|
193
191
|
)
|
|
194
192
|
else:
|
|
195
|
-
token_addr =
|
|
196
|
-
|
|
193
|
+
token_addr = to_checksum_address(underlying_token)
|
|
194
|
+
transaction = await self._encode_call(
|
|
197
195
|
target=self.pool_address,
|
|
198
196
|
abi=POOL_ABI,
|
|
199
197
|
fn_name="withdraw",
|
|
@@ -201,36 +199,10 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
201
199
|
from_address=strategy,
|
|
202
200
|
chain_id=chain_id,
|
|
203
201
|
)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
# ------------------------------------------------------------------ #
|
|
207
|
-
# Helpers #
|
|
208
|
-
# ------------------------------------------------------------------ #
|
|
209
|
-
|
|
210
|
-
async def _send_tx(self, tx: dict[str, Any]) -> tuple[bool, Any]:
|
|
211
|
-
txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
212
|
-
return True, txn_hash
|
|
213
|
-
|
|
214
|
-
async def _ensure_allowance(
|
|
215
|
-
self,
|
|
216
|
-
*,
|
|
217
|
-
token_address: str,
|
|
218
|
-
owner: str,
|
|
219
|
-
spender: str,
|
|
220
|
-
amount: int,
|
|
221
|
-
chain_id: int,
|
|
222
|
-
) -> tuple[bool, Any]:
|
|
223
|
-
allowance = await get_token_allowance(token_address, chain_id, owner, spender)
|
|
224
|
-
if allowance >= amount:
|
|
225
|
-
return True, {}
|
|
226
|
-
approve_tx = await build_approve_transaction(
|
|
227
|
-
from_address=owner,
|
|
228
|
-
chain_id=chain_id,
|
|
229
|
-
token_address=token_address,
|
|
230
|
-
spender_address=spender,
|
|
231
|
-
amount=amount,
|
|
202
|
+
txn_hash = await send_transaction(
|
|
203
|
+
transaction, self.strategy_wallet_signing_callback
|
|
232
204
|
)
|
|
233
|
-
return
|
|
205
|
+
return True, txn_hash
|
|
234
206
|
|
|
235
207
|
async def _encode_call(
|
|
236
208
|
self,
|
|
@@ -254,35 +226,16 @@ class HyperlendAdapter(BaseAdapter):
|
|
|
254
226
|
except ValueError as exc:
|
|
255
227
|
raise ValueError(f"Failed to encode {fn_name}: {exc}") from exc
|
|
256
228
|
|
|
257
|
-
|
|
229
|
+
transaction: dict[str, Any] = {
|
|
258
230
|
"chainId": int(chain_id),
|
|
259
231
|
"from": to_checksum_address(from_address),
|
|
260
232
|
"to": to_checksum_address(target),
|
|
261
233
|
"data": data,
|
|
262
234
|
"value": int(value),
|
|
263
235
|
}
|
|
264
|
-
return
|
|
265
|
-
|
|
266
|
-
def _strategy_address(self) -> str:
|
|
267
|
-
addr = None
|
|
268
|
-
if isinstance(self.strategy_wallet, dict):
|
|
269
|
-
addr = self.strategy_wallet.get("address") or (
|
|
270
|
-
(self.strategy_wallet.get("evm") or {}).get("address")
|
|
271
|
-
)
|
|
272
|
-
elif isinstance(self.strategy_wallet, str):
|
|
273
|
-
addr = self.strategy_wallet
|
|
274
|
-
if not addr:
|
|
275
|
-
raise ValueError(
|
|
276
|
-
"strategy_wallet address is required for HyperLend operations"
|
|
277
|
-
)
|
|
278
|
-
return to_checksum_address(addr)
|
|
236
|
+
return transaction
|
|
279
237
|
|
|
280
238
|
def _gateway_first_arg(self, underlying_token: str) -> str:
|
|
281
239
|
if self.gateway_deposit_takes_pool:
|
|
282
240
|
return self.pool_address
|
|
283
|
-
return
|
|
284
|
-
|
|
285
|
-
def _checksum(self, address: str | None) -> str:
|
|
286
|
-
if not address:
|
|
287
|
-
raise ValueError("Missing required contract address in HyperLend config")
|
|
288
|
-
return to_checksum_address(address)
|
|
241
|
+
return to_checksum_address(underlying_token)
|
|
@@ -14,7 +14,11 @@ class TestHyperlendAdapter:
|
|
|
14
14
|
@pytest.fixture
|
|
15
15
|
def adapter(self, mock_hyperlend_client):
|
|
16
16
|
adapter = HyperlendAdapter(
|
|
17
|
-
config={
|
|
17
|
+
config={
|
|
18
|
+
"strategy_wallet": {
|
|
19
|
+
"address": "0x1234567890123456789012345678901234567890"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
18
22
|
)
|
|
19
23
|
adapter.hyperlend_client = mock_hyperlend_client
|
|
20
24
|
return adapter
|
|
@@ -5,17 +5,18 @@ import time
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
6
|
|
|
7
7
|
from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
|
|
8
|
+
from wayfinder_paths.core.constants.contracts import (
|
|
9
|
+
ARBITRUM_USDC,
|
|
10
|
+
HYPERLIQUID_BRIDGE,
|
|
11
|
+
)
|
|
8
12
|
|
|
9
13
|
if TYPE_CHECKING:
|
|
10
14
|
from wayfinder_paths.core.clients.protocols import (
|
|
11
15
|
HyperliquidExecutorProtocol as HyperliquidExecutor,
|
|
12
16
|
)
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# USDC contract on Arbitrum
|
|
18
|
-
ARBITRUM_USDC_ADDRESS = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
|
|
18
|
+
HYPERLIQUID_BRIDGE_ADDRESS = HYPERLIQUID_BRIDGE
|
|
19
|
+
ARBITRUM_USDC_ADDRESS = ARBITRUM_USDC
|
|
19
20
|
|
|
20
21
|
try:
|
|
21
22
|
from hyperliquid.info import Info
|
|
@@ -46,7 +46,10 @@ success, data = await adapter.get_strategy_net_deposit(
|
|
|
46
46
|
wallet_address="0x..."
|
|
47
47
|
)
|
|
48
48
|
if success:
|
|
49
|
-
net_deposit = data
|
|
49
|
+
net_deposit = float(data) if data is not None else 0
|
|
50
|
+
print(f"Net deposit: {net_deposit} USDC")
|
|
51
|
+
else:
|
|
52
|
+
print(f"Error: {data}")
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
### record_deposit
|
|
@@ -4,7 +4,6 @@ from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
|
|
|
4
4
|
from wayfinder_paths.core.adapters.models import Operation
|
|
5
5
|
from wayfinder_paths.core.clients.LedgerClient import (
|
|
6
6
|
LedgerClient,
|
|
7
|
-
NetDeposit,
|
|
8
7
|
StrategyTransactionList,
|
|
9
8
|
TransactionRecord,
|
|
10
9
|
)
|
|
@@ -36,7 +35,7 @@ class LedgerAdapter(BaseAdapter):
|
|
|
36
35
|
|
|
37
36
|
async def get_strategy_net_deposit(
|
|
38
37
|
self, wallet_address: str
|
|
39
|
-
) -> tuple[bool,
|
|
38
|
+
) -> tuple[bool, float | str]:
|
|
40
39
|
try:
|
|
41
40
|
data = await self.ledger_client.get_strategy_net_deposit(
|
|
42
41
|
wallet_address=wallet_address
|
|
@@ -116,9 +115,10 @@ class LedgerAdapter(BaseAdapter):
|
|
|
116
115
|
strategy_name: str | None = None,
|
|
117
116
|
) -> tuple[bool, TransactionRecord | str]:
|
|
118
117
|
try:
|
|
118
|
+
op_dict = operation_data.model_dump(mode="json")
|
|
119
119
|
result = await self.ledger_client.add_strategy_operation(
|
|
120
120
|
wallet_address=wallet_address,
|
|
121
|
-
operation_data=
|
|
121
|
+
operation_data=op_dict,
|
|
122
122
|
usd_value=usd_value,
|
|
123
123
|
strategy_name=strategy_name,
|
|
124
124
|
)
|