wayfinder-paths 0.1.13__py3-none-any.whl → 0.1.14__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.

Files changed (47) hide show
  1. wayfinder_paths/adapters/balance_adapter/README.md +13 -14
  2. wayfinder_paths/adapters/balance_adapter/adapter.py +33 -32
  3. wayfinder_paths/adapters/balance_adapter/test_adapter.py +123 -0
  4. wayfinder_paths/adapters/brap_adapter/README.md +11 -16
  5. wayfinder_paths/adapters/brap_adapter/adapter.py +78 -63
  6. wayfinder_paths/adapters/brap_adapter/examples.json +63 -52
  7. wayfinder_paths/adapters/brap_adapter/test_adapter.py +121 -59
  8. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +16 -14
  9. wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +114 -60
  10. wayfinder_paths/adapters/pool_adapter/README.md +9 -10
  11. wayfinder_paths/adapters/pool_adapter/adapter.py +9 -10
  12. wayfinder_paths/adapters/token_adapter/README.md +2 -14
  13. wayfinder_paths/adapters/token_adapter/adapter.py +16 -10
  14. wayfinder_paths/adapters/token_adapter/examples.json +4 -8
  15. wayfinder_paths/adapters/token_adapter/test_adapter.py +5 -3
  16. wayfinder_paths/core/clients/BRAPClient.py +102 -61
  17. wayfinder_paths/core/clients/ClientManager.py +1 -68
  18. wayfinder_paths/core/clients/HyperlendClient.py +125 -64
  19. wayfinder_paths/core/clients/LedgerClient.py +1 -4
  20. wayfinder_paths/core/clients/PoolClient.py +122 -48
  21. wayfinder_paths/core/clients/TokenClient.py +91 -36
  22. wayfinder_paths/core/clients/WalletClient.py +26 -56
  23. wayfinder_paths/core/clients/WayfinderClient.py +28 -160
  24. wayfinder_paths/core/clients/__init__.py +0 -2
  25. wayfinder_paths/core/clients/protocols.py +35 -46
  26. wayfinder_paths/core/clients/sdk_example.py +37 -22
  27. wayfinder_paths/core/engine/StrategyJob.py +7 -55
  28. wayfinder_paths/core/services/local_evm_txn.py +6 -6
  29. wayfinder_paths/core/services/local_token_txn.py +1 -1
  30. wayfinder_paths/core/strategies/Strategy.py +0 -2
  31. wayfinder_paths/core/utils/evm_helpers.py +2 -2
  32. wayfinder_paths/run_strategy.py +8 -19
  33. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +10 -11
  34. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +40 -25
  35. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +54 -9
  36. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +3 -3
  37. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/test_strategy.py +12 -6
  38. wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +1 -1
  39. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +88 -56
  40. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +16 -12
  41. wayfinder_paths/templates/strategy/README.md +3 -3
  42. wayfinder_paths/templates/strategy/test_strategy.py +3 -2
  43. {wayfinder_paths-0.1.13.dist-info → wayfinder_paths-0.1.14.dist-info}/METADATA +14 -49
  44. {wayfinder_paths-0.1.13.dist-info → wayfinder_paths-0.1.14.dist-info}/RECORD +46 -47
  45. wayfinder_paths/core/clients/AuthClient.py +0 -83
  46. {wayfinder_paths-0.1.13.dist-info → wayfinder_paths-0.1.14.dist-info}/LICENSE +0 -0
  47. {wayfinder_paths-0.1.13.dist-info → wayfinder_paths-0.1.14.dist-info}/WHEEL +0 -0
@@ -14,25 +14,37 @@
14
14
  "output": {
15
15
  "success": true,
16
16
  "data": {
17
- "quotes": {
18
- "best_quote": {
19
- "input_amount": "1000000000000000000",
20
- "output_amount": "995000000000000000",
21
- "gas_fee": "5000000000000000",
22
- "bridge_fee": "2000000000000000",
23
- "protocol_fee": "1000000000000000",
24
- "total_fee": "8000000000000000",
25
- "slippage": 0.01,
26
- "price_impact": 0.005,
27
- "estimated_time": 300
28
- },
29
- "quotes": [
30
- {
31
- "route": "Route 1",
32
- "output_amount": "995000000000000000",
33
- "total_fee": "8000000000000000"
17
+ "quotes": [
18
+ {
19
+ "provider": "enso",
20
+ "input_amount": 1000000000000000000,
21
+ "output_amount": 995000000000000000,
22
+ "fee_estimate": {
23
+ "fee_total_usd": 0.08,
24
+ "fee_breakdown": []
25
+ },
26
+ "calldata": {
27
+ "data": "0x",
28
+ "to": "0x",
29
+ "value": "0",
30
+ "chainId": 8453
34
31
  }
35
- ]
32
+ }
33
+ ],
34
+ "best_quote": {
35
+ "provider": "enso",
36
+ "input_amount": 1000000000000000000,
37
+ "output_amount": 995000000000000000,
38
+ "fee_estimate": {
39
+ "fee_total_usd": 0.08,
40
+ "fee_breakdown": []
41
+ },
42
+ "calldata": {
43
+ "data": "0x",
44
+ "to": "0x",
45
+ "value": "0",
46
+ "chainId": 8453
47
+ }
36
48
  }
37
49
  }
38
50
  }
@@ -52,15 +64,19 @@
52
64
  "output": {
53
65
  "success": true,
54
66
  "data": {
55
- "input_amount": "1000000000000000000",
56
- "output_amount": "995000000000000000",
57
- "gas_fee": "5000000000000000",
58
- "bridge_fee": "2000000000000000",
59
- "protocol_fee": "1000000000000000",
60
- "total_fee": "8000000000000000",
61
- "slippage": 0.01,
62
- "price_impact": 0.005,
63
- "estimated_time": 300
67
+ "provider": "enso",
68
+ "input_amount": 1000000000000000000,
69
+ "output_amount": 995000000000000000,
70
+ "fee_estimate": {
71
+ "fee_total_usd": 0.08,
72
+ "fee_breakdown": []
73
+ },
74
+ "calldata": {
75
+ "data": "0x",
76
+ "to": "0x",
77
+ "value": "0",
78
+ "chainId": 8453
79
+ }
64
80
  }
65
81
  }
66
82
  },
@@ -77,14 +93,14 @@
77
93
  "output": {
78
94
  "success": true,
79
95
  "data": {
80
- "input_amount": "1000000000000000000",
81
- "output_amount": "995000000000000000",
82
- "gas_fee": "5000000000000000",
83
- "bridge_fee": "2000000000000000",
84
- "protocol_fee": "1000000000000000",
85
- "total_fee": "8000000000000000",
86
- "slippage": 0.01,
87
- "price_impact": 0.005
96
+ "input_amount": 1000000000000000000,
97
+ "output_amount": 995000000000000000,
98
+ "gas_fee": 567840,
99
+ "bridge_fee": 0,
100
+ "protocol_fee": 0.08,
101
+ "total_fee": 0.08,
102
+ "slippage": 0,
103
+ "price_impact": 6888
88
104
  }
89
105
  }
90
106
  },
@@ -101,35 +117,30 @@
101
117
  "output": {
102
118
  "success": true,
103
119
  "data": {
104
- "total_routes": 3,
120
+ "total_routes": 2,
105
121
  "best_route": {
106
- "input_amount": "1000000000000000000",
107
- "output_amount": "995000000000000000",
108
- "total_fee": "8000000000000000"
122
+ "provider": "enso",
123
+ "output_amount": 995000000000000000,
124
+ "fee_estimate": { "fee_total_usd": 0.08, "fee_breakdown": [] }
109
125
  },
110
126
  "all_routes": [
111
127
  {
112
- "route": "Route 1",
113
- "output_amount": "995000000000000000",
114
- "total_fee": "8000000000000000",
115
- "estimated_time": 300
128
+ "provider": "enso",
129
+ "output_amount": 995000000000000000,
130
+ "fee_estimate": { "fee_total_usd": 0.08, "fee_breakdown": [] }
116
131
  },
117
132
  {
118
- "route": "Route 2",
119
- "output_amount": "992000000000000000",
120
- "total_fee": "12000000000000000",
121
- "estimated_time": 180
133
+ "provider": "enso",
134
+ "output_amount": 992000000000000000,
135
+ "fee_estimate": { "fee_total_usd": 0.12, "fee_breakdown": [] }
122
136
  }
123
137
  ],
124
138
  "route_analysis": {
125
139
  "highest_output": {
126
- "output_amount": "995000000000000000"
140
+ "output_amount": 995000000000000000
127
141
  },
128
142
  "lowest_fees": {
129
- "total_fee": "8000000000000000"
130
- },
131
- "fastest": {
132
- "estimated_time": 180
143
+ "fee_estimate": { "fee_total_usd": 0.08, "fee_breakdown": [] }
133
144
  }
134
145
  }
135
146
  }
@@ -41,14 +41,34 @@ class TestBRAPAdapter:
41
41
  async def test_get_swap_quote_success(self, adapter, mock_brap_client):
42
42
  """Test successful swap quote retrieval"""
43
43
  mock_response = {
44
- "quotes": {
45
- "best_quote": {
46
- "input_amount": "1000000000000000000",
47
- "output_amount": "995000000000000000",
48
- "gas_fee": "5000000000000000",
49
- "total_fee": "8000000000000000",
44
+ "quotes": [
45
+ {
46
+ "provider": "enso",
47
+ "input_amount": 1000000000000000000,
48
+ "output_amount": 995000000000000000,
49
+ "calldata": {
50
+ "data": "0x",
51
+ "to": "0x",
52
+ "from_address": "0x",
53
+ "value": "0",
54
+ "chainId": 8453,
55
+ },
56
+ "fee_estimate": {"fee_total_usd": 0.008, "fee_breakdown": []},
50
57
  }
51
- }
58
+ ],
59
+ "best_quote": {
60
+ "provider": "enso",
61
+ "input_amount": 1000000000000000000,
62
+ "output_amount": 995000000000000000,
63
+ "calldata": {
64
+ "data": "0x",
65
+ "to": "0x",
66
+ "from_address": "0x",
67
+ "value": "0",
68
+ "chainId": 8453,
69
+ },
70
+ "fee_estimate": {"fee_total_usd": 0.008, "fee_breakdown": []},
71
+ },
52
72
  }
53
73
  mock_brap_client.get_quote = AsyncMock(return_value=mock_response)
54
74
 
@@ -66,26 +86,32 @@ class TestBRAPAdapter:
66
86
  assert success is True
67
87
  assert data == mock_response
68
88
  mock_brap_client.get_quote.assert_called_once_with(
69
- from_token_address="0x" + "a" * 40,
70
- to_token_address="0x" + "b" * 40,
71
- from_chain_id=8453,
72
- to_chain_id=1,
73
- from_address="0x1234567890123456789012345678901234567890",
74
- to_address="0x1234567890123456789012345678901234567890",
75
- amount1="1000000000000000000",
76
- slippage=0.01,
77
- wayfinder_fee=None,
89
+ from_token="0x" + "a" * 40,
90
+ to_token="0x" + "b" * 40,
91
+ from_chain=8453,
92
+ to_chain=1,
93
+ from_wallet="0x1234567890123456789012345678901234567890",
94
+ from_amount="1000000000000000000",
78
95
  )
79
96
 
80
97
  @pytest.mark.asyncio
81
98
  async def test_get_best_quote_success(self, adapter, mock_brap_client):
82
99
  """Test successful best quote retrieval"""
83
100
  mock_response = {
84
- "best_route": {
85
- "input_amount": "1000000000000000000",
86
- "output_amount": "995000000000000000",
87
- "total_fee": "8000000000000000",
88
- }
101
+ "quotes": [],
102
+ "best_quote": {
103
+ "provider": "enso",
104
+ "input_amount": 1000000000000000000,
105
+ "output_amount": 995000000000000000,
106
+ "calldata": {
107
+ "data": "0x",
108
+ "to": "0x",
109
+ "from_address": "0x",
110
+ "value": "0",
111
+ "chainId": 8453,
112
+ },
113
+ "fee_estimate": {"fee_total_usd": 0.008, "fee_breakdown": []},
114
+ },
89
115
  }
90
116
  mock_brap_client.get_quote = AsyncMock(return_value=mock_response)
91
117
 
@@ -100,13 +126,13 @@ class TestBRAPAdapter:
100
126
  )
101
127
 
102
128
  assert success is True
103
- assert data["input_amount"] == "1000000000000000000"
104
- assert data["output_amount"] == "995000000000000000"
129
+ assert data["input_amount"] == 1000000000000000000
130
+ assert data["output_amount"] == 995000000000000000
105
131
 
106
132
  @pytest.mark.asyncio
107
133
  async def test_get_best_quote_no_quotes(self, adapter, mock_brap_client):
108
134
  """Test best quote retrieval when no quotes available"""
109
- mock_response = {"best_route": None}
135
+ mock_response = {"quotes": [], "best_quote": None}
110
136
  mock_brap_client.get_quote = AsyncMock(return_value=mock_response)
111
137
 
112
138
  success, data = await adapter.get_best_quote(
@@ -126,18 +152,25 @@ class TestBRAPAdapter:
126
152
  async def test_calculate_swap_fees_success(self, adapter, mock_brap_client):
127
153
  """Test successful swap fee calculation"""
128
154
  mock_quote_response = {
129
- "quotes": {
130
- "best_quote": {
131
- "input_amount": "1000000000000000000",
132
- "output_amount": "995000000000000000",
133
- "gas_fee": "5000000000000000",
134
- "bridge_fee": "2000000000000000",
135
- "protocol_fee": "1000000000000000",
136
- "total_fee": "8000000000000000",
137
- "slippage": 0.01,
138
- "price_impact": 0.005,
139
- }
140
- }
155
+ "quotes": [],
156
+ "best_quote": {
157
+ "provider": "enso",
158
+ "input_amount": 1000000000000000000,
159
+ "output_amount": 995000000000000000,
160
+ "gas_estimate": 5000000000000000,
161
+ "quote": {"priceImpact": 5},
162
+ "fee_estimate": {
163
+ "fee_total_usd": 0.008,
164
+ "fee_breakdown": [],
165
+ },
166
+ "calldata": {
167
+ "data": "0x",
168
+ "to": "0x",
169
+ "from_address": "0x",
170
+ "value": "0",
171
+ "chainId": 8453,
172
+ },
173
+ },
141
174
  }
142
175
  mock_brap_client.get_quote = AsyncMock(return_value=mock_quote_response)
143
176
 
@@ -151,35 +184,53 @@ class TestBRAPAdapter:
151
184
  )
152
185
 
153
186
  assert success is True
154
- assert data["input_amount"] == "1000000000000000000"
155
- assert data["output_amount"] == "995000000000000000"
156
- assert data["gas_fee"] == "5000000000000000"
157
- assert data["total_fee"] == "8000000000000000"
187
+ assert data["input_amount"] == 1000000000000000000
188
+ assert data["output_amount"] == 995000000000000000
189
+ assert data["gas_fee"] == 5000000000000000
190
+ assert data["total_fee"] == 0.008
158
191
 
159
192
  @pytest.mark.asyncio
160
193
  async def test_compare_routes_success(self, adapter, mock_brap_client):
161
194
  """Test successful route comparison"""
162
195
  mock_response = {
163
- "quotes": {
164
- "quotes": [
165
- {
166
- "route": "Route 1",
167
- "output_amount": "995000000000000000",
168
- "total_fee": "8000000000000000",
169
- "estimated_time": 300,
196
+ "quotes": [
197
+ {
198
+ "provider": "enso",
199
+ "output_amount": 995000000000000000,
200
+ "fee_estimate": {"fee_total_usd": 0.008, "fee_breakdown": []},
201
+ "calldata": {
202
+ "data": "0x",
203
+ "to": "0x",
204
+ "from_address": "0x",
205
+ "value": "0",
206
+ "chainId": 8453,
170
207
  },
171
- {
172
- "route": "Route 2",
173
- "output_amount": "992000000000000000",
174
- "total_fee": "12000000000000000",
175
- "estimated_time": 180,
208
+ },
209
+ {
210
+ "provider": "enso",
211
+ "output_amount": 992000000000000000,
212
+ "fee_estimate": {"fee_total_usd": 0.012, "fee_breakdown": []},
213
+ "calldata": {
214
+ "data": "0x",
215
+ "to": "0x",
216
+ "from_address": "0x",
217
+ "value": "0",
218
+ "chainId": 8453,
176
219
  },
177
- ],
178
- "best_quote": {
179
- "output_amount": "995000000000000000",
180
- "total_fee": "8000000000000000",
181
220
  },
182
- }
221
+ ],
222
+ "best_quote": {
223
+ "provider": "enso",
224
+ "output_amount": 995000000000000000,
225
+ "fee_estimate": {"fee_total_usd": 0.008, "fee_breakdown": []},
226
+ "calldata": {
227
+ "data": "0x",
228
+ "to": "0x",
229
+ "from_address": "0x",
230
+ "value": "0",
231
+ "chainId": 8453,
232
+ },
233
+ },
183
234
  }
184
235
  mock_brap_client.get_quote = AsyncMock(return_value=mock_response)
185
236
 
@@ -194,7 +245,7 @@ class TestBRAPAdapter:
194
245
  assert success is True
195
246
  assert data["total_routes"] == 2
196
247
  assert len(data["all_routes"]) == 2
197
- assert data["best_route"]["output_amount"] == "995000000000000000"
248
+ assert data["best_route"]["output_amount"] == 995000000000000000
198
249
 
199
250
  @pytest.mark.asyncio
200
251
  async def test_estimate_gas_cost_success(self, adapter):
@@ -214,7 +265,18 @@ class TestBRAPAdapter:
214
265
  async def test_validate_swap_parameters_success(self, adapter, mock_brap_client):
215
266
  """Test successful swap parameter validation"""
216
267
  mock_quote_response = {
217
- "quotes": {"best_quote": {"output_amount": "995000000000000000"}}
268
+ "quotes": [],
269
+ "best_quote": {
270
+ "output_amount": 995000000000000000,
271
+ "calldata": {
272
+ "data": "0x",
273
+ "to": "0x",
274
+ "from_address": "0x",
275
+ "value": "0",
276
+ "chainId": 8453,
277
+ },
278
+ "fee_estimate": {"fee_total_usd": 0.008, "fee_breakdown": []},
279
+ },
218
280
  }
219
281
  mock_brap_client.get_quote = AsyncMock(return_value=mock_quote_response)
220
282
 
@@ -10,7 +10,7 @@ from wayfinder_paths.core.clients.HyperlendClient import (
10
10
  HyperlendClient,
11
11
  LendRateHistory,
12
12
  MarketEntry,
13
- StableMarket,
13
+ StableMarketsHeadroomResponse,
14
14
  )
15
15
  from wayfinder_paths.core.constants.base import DEFAULT_TRANSACTION_TIMEOUT
16
16
  from wayfinder_paths.core.constants.hyperlend_abi import (
@@ -66,55 +66,57 @@ class HyperlendAdapter(BaseAdapter):
66
66
 
67
67
  async def get_stable_markets(
68
68
  self,
69
- chain_id: int,
69
+ *,
70
70
  required_underlying_tokens: float | None = None,
71
71
  buffer_bps: int | None = None,
72
72
  min_buffer_tokens: float | None = None,
73
- is_stable_symbol: bool | None = None,
74
- ) -> tuple[bool, list[StableMarket] | str]:
73
+ ) -> tuple[bool, StableMarketsHeadroomResponse | str]:
75
74
  try:
76
75
  data = await self.hyperlend_client.get_stable_markets(
77
- chain_id=chain_id,
78
76
  required_underlying_tokens=required_underlying_tokens,
79
77
  buffer_bps=buffer_bps,
80
78
  min_buffer_tokens=min_buffer_tokens,
81
- is_stable_symbol=is_stable_symbol,
82
79
  )
83
80
  return True, data
84
81
  except Exception as exc:
85
82
  return False, str(exc)
86
83
 
87
84
  async def get_assets_view(
88
- self, chain_id: int, user_address: str
85
+ self,
86
+ *,
87
+ user_address: str,
89
88
  ) -> tuple[bool, AssetsView | str]:
90
89
  try:
91
90
  data = await self.hyperlend_client.get_assets_view(
92
- chain_id=chain_id, user_address=user_address
91
+ user_address=user_address
93
92
  )
94
93
  return True, data
95
94
  except Exception as exc:
96
95
  return False, str(exc)
97
96
 
98
97
  async def get_market_entry(
99
- self, chain_id: int, underlying: str
98
+ self,
99
+ *,
100
+ token: str,
100
101
  ) -> tuple[bool, MarketEntry | str]:
101
102
  try:
102
- data = await self.hyperlend_client.get_market_entry(chain_id, underlying)
103
+ data = await self.hyperlend_client.get_market_entry(token=token)
103
104
  return True, data
104
105
  except Exception as exc:
105
106
  return False, str(exc)
106
107
 
107
108
  async def get_lend_rate_history(
108
109
  self,
109
- chain_id: int,
110
- token_address: str,
110
+ *,
111
+ token: str,
111
112
  lookback_hours: int,
113
+ force_refresh: bool | None = None,
112
114
  ) -> tuple[bool, LendRateHistory | str]:
113
115
  try:
114
116
  data = await self.hyperlend_client.get_lend_rate_history(
115
- chain_id=chain_id,
116
- token_address=token_address,
117
+ token=token,
117
118
  lookback_hours=lookback_hours,
119
+ force_refresh=force_refresh,
118
120
  )
119
121
  return True, data
120
122
  except Exception as exc: