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
|
@@ -8,49 +8,43 @@ from eth_utils import to_checksum_address
|
|
|
8
8
|
|
|
9
9
|
from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
|
|
10
10
|
from wayfinder_paths.core.clients.TokenClient import TokenClient
|
|
11
|
+
from wayfinder_paths.core.constants.base import MANTISSA, MAX_UINT256, SECONDS_PER_YEAR
|
|
12
|
+
from wayfinder_paths.core.constants.chains import CHAIN_ID_BASE
|
|
13
|
+
from wayfinder_paths.core.constants.contracts import (
|
|
14
|
+
BASE_USDC,
|
|
15
|
+
BASE_WETH,
|
|
16
|
+
BASE_WSTETH,
|
|
17
|
+
MOONWELL_COMPTROLLER,
|
|
18
|
+
MOONWELL_M_USDC,
|
|
19
|
+
MOONWELL_M_WETH,
|
|
20
|
+
MOONWELL_M_WSTETH,
|
|
21
|
+
MOONWELL_REWARD_DISTRIBUTOR,
|
|
22
|
+
MOONWELL_WELL_TOKEN,
|
|
23
|
+
)
|
|
11
24
|
from wayfinder_paths.core.constants.moonwell_abi import (
|
|
12
25
|
COMPTROLLER_ABI,
|
|
13
26
|
MTOKEN_ABI,
|
|
14
27
|
REWARD_DISTRIBUTOR_ABI,
|
|
15
28
|
WETH_ABI,
|
|
16
29
|
)
|
|
17
|
-
from wayfinder_paths.core.utils.tokens import
|
|
18
|
-
build_approve_transaction,
|
|
19
|
-
get_token_allowance,
|
|
20
|
-
)
|
|
30
|
+
from wayfinder_paths.core.utils.tokens import ensure_allowance
|
|
21
31
|
from wayfinder_paths.core.utils.transaction import send_transaction
|
|
22
32
|
from wayfinder_paths.core.utils.web3 import web3_from_chain_id
|
|
23
33
|
|
|
24
|
-
# Moonwell Base chain addresses
|
|
25
34
|
MOONWELL_DEFAULTS = {
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
"reward_distributor": "0xe9005b078701e2a0948d2eac43010d35870ad9d2",
|
|
36
|
-
"comptroller": "0xfbb21d0380bee3312b33c4353c8936a0f13ef26c",
|
|
37
|
-
# WELL token address on Base
|
|
38
|
-
"well_token": "0xA88594D404727625A9437C3f886C7643872296AE",
|
|
35
|
+
"m_usdc": MOONWELL_M_USDC,
|
|
36
|
+
"m_weth": MOONWELL_M_WETH,
|
|
37
|
+
"m_wsteth": MOONWELL_M_WSTETH,
|
|
38
|
+
"usdc": BASE_USDC,
|
|
39
|
+
"weth": BASE_WETH,
|
|
40
|
+
"wsteth": BASE_WSTETH,
|
|
41
|
+
"reward_distributor": MOONWELL_REWARD_DISTRIBUTOR,
|
|
42
|
+
"comptroller": MOONWELL_COMPTROLLER,
|
|
43
|
+
"well_token": MOONWELL_WELL_TOKEN,
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
BASE_CHAIN_ID = 8453
|
|
43
|
-
|
|
44
|
-
# Mantissa for collateral factor calculations (1e18)
|
|
45
|
-
MANTISSA = 10**18
|
|
46
|
-
|
|
47
|
-
# Seconds per year for APY calculations
|
|
48
|
-
SECONDS_PER_YEAR = 365 * 24 * 60 * 60
|
|
49
|
-
|
|
50
|
-
# Collateral factor cache TTL (1 hour - rarely changes, governance controlled)
|
|
46
|
+
BASE_CHAIN_ID = CHAIN_ID_BASE
|
|
51
47
|
CF_CACHE_TTL = 3600
|
|
52
|
-
|
|
53
|
-
# Default retry settings for rate-limited RPCs
|
|
54
48
|
DEFAULT_MAX_RETRIES = 5
|
|
55
49
|
DEFAULT_BASE_DELAY = 3.0
|
|
56
50
|
|
|
@@ -80,45 +74,49 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
80
74
|
self.token_client = token_client
|
|
81
75
|
self.strategy_wallet_signing_callback = strategy_wallet_signing_callback
|
|
82
76
|
|
|
83
|
-
|
|
77
|
+
strategy_wallet = cfg.get("strategy_wallet") or {}
|
|
78
|
+
strategy_addr = strategy_wallet.get("address")
|
|
79
|
+
if not strategy_addr:
|
|
80
|
+
raise ValueError("strategy_wallet.address is required")
|
|
81
|
+
self.strategy_wallet_address = to_checksum_address(strategy_addr)
|
|
84
82
|
self.chain_id = adapter_cfg.get("chain_id", BASE_CHAIN_ID)
|
|
85
83
|
self.chain_name = "base"
|
|
86
84
|
|
|
87
85
|
# Protocol addresses (with config overrides)
|
|
88
|
-
self.comptroller_address =
|
|
86
|
+
self.comptroller_address = to_checksum_address(
|
|
89
87
|
adapter_cfg.get("comptroller") or MOONWELL_DEFAULTS["comptroller"]
|
|
90
88
|
)
|
|
91
|
-
self.reward_distributor_address =
|
|
89
|
+
self.reward_distributor_address = to_checksum_address(
|
|
92
90
|
adapter_cfg.get("reward_distributor")
|
|
93
91
|
or MOONWELL_DEFAULTS["reward_distributor"]
|
|
94
92
|
)
|
|
95
|
-
self.well_token =
|
|
93
|
+
self.well_token = to_checksum_address(
|
|
96
94
|
adapter_cfg.get("well_token") or MOONWELL_DEFAULTS["well_token"]
|
|
97
95
|
)
|
|
98
96
|
|
|
99
97
|
# Token addresses
|
|
100
|
-
self.m_usdc =
|
|
98
|
+
self.m_usdc = to_checksum_address(
|
|
101
99
|
adapter_cfg.get("m_usdc") or MOONWELL_DEFAULTS["m_usdc"]
|
|
102
100
|
)
|
|
103
|
-
self.m_weth =
|
|
101
|
+
self.m_weth = to_checksum_address(
|
|
104
102
|
adapter_cfg.get("m_weth") or MOONWELL_DEFAULTS["m_weth"]
|
|
105
103
|
)
|
|
106
|
-
self.m_wsteth =
|
|
104
|
+
self.m_wsteth = to_checksum_address(
|
|
107
105
|
adapter_cfg.get("m_wsteth") or MOONWELL_DEFAULTS["m_wsteth"]
|
|
108
106
|
)
|
|
109
|
-
self.usdc =
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
self.usdc = to_checksum_address(
|
|
108
|
+
adapter_cfg.get("usdc") or MOONWELL_DEFAULTS["usdc"]
|
|
109
|
+
)
|
|
110
|
+
self.weth = to_checksum_address(
|
|
111
|
+
adapter_cfg.get("weth") or MOONWELL_DEFAULTS["weth"]
|
|
112
|
+
)
|
|
113
|
+
self.wsteth = to_checksum_address(
|
|
112
114
|
adapter_cfg.get("wsteth") or MOONWELL_DEFAULTS["wsteth"]
|
|
113
115
|
)
|
|
114
116
|
|
|
115
117
|
# Collateral factor cache: mtoken -> (value, timestamp)
|
|
116
118
|
self._cf_cache: dict[str, tuple[float, float]] = {}
|
|
117
119
|
|
|
118
|
-
# ------------------------------------------------------------------ #
|
|
119
|
-
# Public API - Lending Operations #
|
|
120
|
-
# ------------------------------------------------------------------ #
|
|
121
|
-
|
|
122
120
|
async def lend(
|
|
123
121
|
self,
|
|
124
122
|
*,
|
|
@@ -126,20 +124,23 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
126
124
|
underlying_token: str,
|
|
127
125
|
amount: int,
|
|
128
126
|
) -> tuple[bool, Any]:
|
|
129
|
-
strategy = self.
|
|
127
|
+
strategy = self.strategy_wallet_address
|
|
130
128
|
amount = int(amount)
|
|
131
129
|
if amount <= 0:
|
|
132
130
|
return False, "amount must be positive"
|
|
133
131
|
|
|
134
|
-
mtoken =
|
|
135
|
-
underlying_token =
|
|
132
|
+
mtoken = to_checksum_address(mtoken)
|
|
133
|
+
underlying_token = to_checksum_address(underlying_token)
|
|
136
134
|
|
|
137
135
|
# Approve mToken to spend underlying tokens
|
|
138
|
-
approved = await
|
|
136
|
+
approved = await ensure_allowance(
|
|
139
137
|
token_address=underlying_token,
|
|
140
138
|
owner=strategy,
|
|
141
139
|
spender=mtoken,
|
|
142
140
|
amount=amount,
|
|
141
|
+
chain_id=self.chain_id,
|
|
142
|
+
signing_callback=self.strategy_wallet_signing_callback,
|
|
143
|
+
approval_amount=MAX_UINT256,
|
|
143
144
|
)
|
|
144
145
|
if not approved[0]:
|
|
145
146
|
return approved
|
|
@@ -152,7 +153,8 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
152
153
|
args=[amount],
|
|
153
154
|
from_address=strategy,
|
|
154
155
|
)
|
|
155
|
-
|
|
156
|
+
txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
157
|
+
return (True, txn_hash)
|
|
156
158
|
|
|
157
159
|
async def unlend(
|
|
158
160
|
self,
|
|
@@ -160,12 +162,12 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
160
162
|
mtoken: str,
|
|
161
163
|
amount: int,
|
|
162
164
|
) -> tuple[bool, Any]:
|
|
163
|
-
strategy = self.
|
|
165
|
+
strategy = self.strategy_wallet_address
|
|
164
166
|
amount = int(amount)
|
|
165
167
|
if amount <= 0:
|
|
166
168
|
return False, "amount must be positive"
|
|
167
169
|
|
|
168
|
-
mtoken =
|
|
170
|
+
mtoken = to_checksum_address(mtoken)
|
|
169
171
|
|
|
170
172
|
# Redeem mTokens for underlying
|
|
171
173
|
tx = await self._encode_call(
|
|
@@ -175,11 +177,8 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
175
177
|
args=[amount],
|
|
176
178
|
from_address=strategy,
|
|
177
179
|
)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
# ------------------------------------------------------------------ #
|
|
181
|
-
# Public API - Borrowing Operations #
|
|
182
|
-
# ------------------------------------------------------------------ #
|
|
180
|
+
txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
181
|
+
return (True, txn_hash)
|
|
183
182
|
|
|
184
183
|
async def borrow(
|
|
185
184
|
self,
|
|
@@ -187,14 +186,12 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
187
186
|
mtoken: str,
|
|
188
187
|
amount: int,
|
|
189
188
|
) -> tuple[bool, Any]:
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
strategy = self._strategy_address()
|
|
189
|
+
strategy = self.strategy_wallet_address
|
|
193
190
|
amount = int(amount)
|
|
194
191
|
if amount <= 0:
|
|
195
192
|
return False, "amount must be positive"
|
|
196
193
|
|
|
197
|
-
mtoken =
|
|
194
|
+
mtoken = to_checksum_address(mtoken)
|
|
198
195
|
|
|
199
196
|
borrow_before = 0
|
|
200
197
|
try:
|
|
@@ -211,15 +208,15 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
211
208
|
{"from": strategy}, block_identifier="pending"
|
|
212
209
|
)
|
|
213
210
|
if borrow_return != 0:
|
|
214
|
-
logger.warning(
|
|
211
|
+
self.logger.warning(
|
|
215
212
|
f"Borrow simulation returned error code {borrow_return}. "
|
|
216
213
|
"Codes: 3=COMPTROLLER_REJECTION, 9=INVALID_ACCOUNT_PAIR, "
|
|
217
214
|
"14=INSUFFICIENT_LIQUIDITY"
|
|
218
215
|
)
|
|
219
216
|
except Exception as call_err:
|
|
220
|
-
logger.debug(f"Borrow simulation failed: {call_err}")
|
|
217
|
+
self.logger.debug(f"Borrow simulation failed: {call_err}")
|
|
221
218
|
except Exception as e:
|
|
222
|
-
logger.warning(f"Failed to get pre-borrow balance: {e}")
|
|
219
|
+
self.logger.warning(f"Failed to get pre-borrow balance: {e}")
|
|
223
220
|
|
|
224
221
|
tx = await self._encode_call(
|
|
225
222
|
target=mtoken,
|
|
@@ -228,10 +225,7 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
228
225
|
args=[amount],
|
|
229
226
|
from_address=strategy,
|
|
230
227
|
)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if not result[0]:
|
|
234
|
-
return result
|
|
228
|
+
txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
235
229
|
|
|
236
230
|
# Verify the borrow actually succeeded by checking balance increased
|
|
237
231
|
try:
|
|
@@ -247,9 +241,7 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
247
241
|
actual_increase = borrow_after - borrow_before
|
|
248
242
|
|
|
249
243
|
if actual_increase < expected_increase:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
logger.error(
|
|
244
|
+
self.logger.error(
|
|
253
245
|
f"Borrow verification failed: balance only increased by "
|
|
254
246
|
f"{actual_increase} (expected ~{amount}). "
|
|
255
247
|
f"Moonwell likely returned an error code. "
|
|
@@ -261,12 +253,9 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
261
253
|
f"Before: {borrow_before}, After: {borrow_after}, Expected: +{amount}",
|
|
262
254
|
)
|
|
263
255
|
except Exception as e:
|
|
264
|
-
|
|
256
|
+
self.logger.warning(f"Could not verify borrow balance: {e}")
|
|
265
257
|
|
|
266
|
-
|
|
267
|
-
# Continue with the original result if verification fails
|
|
268
|
-
|
|
269
|
-
return result
|
|
258
|
+
return (True, txn_hash)
|
|
270
259
|
|
|
271
260
|
async def repay(
|
|
272
261
|
self,
|
|
@@ -276,27 +265,30 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
276
265
|
amount: int,
|
|
277
266
|
repay_full: bool = False,
|
|
278
267
|
) -> tuple[bool, Any]:
|
|
279
|
-
strategy = self.
|
|
268
|
+
strategy = self.strategy_wallet_address
|
|
280
269
|
amount = int(amount)
|
|
281
270
|
if amount <= 0:
|
|
282
271
|
return False, "amount must be positive"
|
|
283
272
|
|
|
284
|
-
mtoken =
|
|
285
|
-
underlying_token =
|
|
273
|
+
mtoken = to_checksum_address(mtoken)
|
|
274
|
+
underlying_token = to_checksum_address(underlying_token)
|
|
286
275
|
|
|
287
276
|
# Approve mToken to spend underlying tokens for repayment
|
|
288
277
|
# When repay_full=True, approve the amount we have, Moonwell will use only what's needed
|
|
289
|
-
approved = await
|
|
278
|
+
approved = await ensure_allowance(
|
|
290
279
|
token_address=underlying_token,
|
|
291
280
|
owner=strategy,
|
|
292
281
|
spender=mtoken,
|
|
293
282
|
amount=amount,
|
|
283
|
+
chain_id=self.chain_id,
|
|
284
|
+
signing_callback=self.strategy_wallet_signing_callback,
|
|
285
|
+
approval_amount=MAX_UINT256,
|
|
294
286
|
)
|
|
295
287
|
if not approved[0]:
|
|
296
288
|
return approved
|
|
297
289
|
|
|
298
290
|
# Use max uint256 for full repayment to avoid balance calculation issues
|
|
299
|
-
repay_amount =
|
|
291
|
+
repay_amount = MAX_UINT256 if repay_full else amount
|
|
300
292
|
|
|
301
293
|
tx = await self._encode_call(
|
|
302
294
|
target=mtoken,
|
|
@@ -305,19 +297,16 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
305
297
|
args=[repay_amount],
|
|
306
298
|
from_address=strategy,
|
|
307
299
|
)
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
# ------------------------------------------------------------------ #
|
|
311
|
-
# Public API - Collateral Management #
|
|
312
|
-
# ------------------------------------------------------------------ #
|
|
300
|
+
txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
301
|
+
return (True, txn_hash)
|
|
313
302
|
|
|
314
303
|
async def set_collateral(
|
|
315
304
|
self,
|
|
316
305
|
*,
|
|
317
306
|
mtoken: str,
|
|
318
307
|
) -> tuple[bool, Any]:
|
|
319
|
-
strategy = self.
|
|
320
|
-
mtoken =
|
|
308
|
+
strategy = self.strategy_wallet_address
|
|
309
|
+
mtoken = to_checksum_address(mtoken)
|
|
321
310
|
|
|
322
311
|
tx = await self._encode_call(
|
|
323
312
|
target=self.comptroller_address,
|
|
@@ -326,10 +315,7 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
326
315
|
args=[[mtoken]],
|
|
327
316
|
from_address=strategy,
|
|
328
317
|
)
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
if not result[0]:
|
|
332
|
-
return result
|
|
318
|
+
txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
333
319
|
|
|
334
320
|
# Verify the market was actually entered
|
|
335
321
|
try:
|
|
@@ -342,9 +328,7 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
342
328
|
).call(block_identifier="pending")
|
|
343
329
|
|
|
344
330
|
if not is_member:
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
logger.error(
|
|
331
|
+
self.logger.error(
|
|
348
332
|
f"set_collateral verification failed: account {strategy} "
|
|
349
333
|
f"is not a member of market {mtoken} after enterMarkets call"
|
|
350
334
|
)
|
|
@@ -353,11 +337,9 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
353
337
|
f"enterMarkets succeeded but account is not a member of market {mtoken}",
|
|
354
338
|
)
|
|
355
339
|
except Exception as e:
|
|
356
|
-
|
|
340
|
+
self.logger.warning(f"Could not verify market membership: {e}")
|
|
357
341
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
return result
|
|
342
|
+
return (True, txn_hash)
|
|
361
343
|
|
|
362
344
|
async def is_market_entered(
|
|
363
345
|
self,
|
|
@@ -366,8 +348,12 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
366
348
|
account: str | None = None,
|
|
367
349
|
) -> tuple[bool, bool | str]:
|
|
368
350
|
try:
|
|
369
|
-
acct =
|
|
370
|
-
|
|
351
|
+
acct = (
|
|
352
|
+
to_checksum_address(account)
|
|
353
|
+
if account
|
|
354
|
+
else self.strategy_wallet_address
|
|
355
|
+
)
|
|
356
|
+
mtoken = to_checksum_address(mtoken)
|
|
371
357
|
|
|
372
358
|
async with web3_from_chain_id(self.chain_id) as web3:
|
|
373
359
|
comptroller = web3.eth.contract(
|
|
@@ -375,7 +361,7 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
375
361
|
)
|
|
376
362
|
is_member = await comptroller.functions.checkMembership(
|
|
377
363
|
acct, mtoken
|
|
378
|
-
).call()
|
|
364
|
+
).call(block_identifier="pending")
|
|
379
365
|
return True, bool(is_member)
|
|
380
366
|
except Exception as exc:
|
|
381
367
|
return False, str(exc)
|
|
@@ -385,8 +371,8 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
385
371
|
*,
|
|
386
372
|
mtoken: str,
|
|
387
373
|
) -> tuple[bool, Any]:
|
|
388
|
-
strategy = self.
|
|
389
|
-
mtoken =
|
|
374
|
+
strategy = self.strategy_wallet_address
|
|
375
|
+
mtoken = to_checksum_address(mtoken)
|
|
390
376
|
|
|
391
377
|
tx = await self._encode_call(
|
|
392
378
|
target=self.comptroller_address,
|
|
@@ -395,18 +381,15 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
395
381
|
args=[mtoken],
|
|
396
382
|
from_address=strategy,
|
|
397
383
|
)
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
# ------------------------------------------------------------------ #
|
|
401
|
-
# Public API - Rewards #
|
|
402
|
-
# ------------------------------------------------------------------ #
|
|
384
|
+
txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
385
|
+
return (True, txn_hash)
|
|
403
386
|
|
|
404
387
|
async def claim_rewards(
|
|
405
388
|
self,
|
|
406
389
|
*,
|
|
407
390
|
min_rewards_usd: float = 0.0,
|
|
408
391
|
) -> tuple[bool, dict[str, int] | str]:
|
|
409
|
-
strategy = self.
|
|
392
|
+
strategy = self.strategy_wallet_address
|
|
410
393
|
|
|
411
394
|
rewards = await self._get_outstanding_rewards(strategy)
|
|
412
395
|
|
|
@@ -427,10 +410,7 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
427
410
|
args=[strategy],
|
|
428
411
|
from_address=strategy,
|
|
429
412
|
)
|
|
430
|
-
|
|
431
|
-
if not result[0]:
|
|
432
|
-
return result
|
|
433
|
-
|
|
413
|
+
await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
434
414
|
return True, rewards
|
|
435
415
|
|
|
436
416
|
async def _get_outstanding_rewards(self, account: str) -> dict[str, int]:
|
|
@@ -476,10 +456,6 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
476
456
|
pass
|
|
477
457
|
return total_usd
|
|
478
458
|
|
|
479
|
-
# ------------------------------------------------------------------ #
|
|
480
|
-
# Public API - Position & Market Data #
|
|
481
|
-
# ------------------------------------------------------------------ #
|
|
482
|
-
|
|
483
459
|
async def get_pos(
|
|
484
460
|
self,
|
|
485
461
|
*,
|
|
@@ -489,8 +465,10 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
489
465
|
max_retries: int = 3,
|
|
490
466
|
block_identifier: int | str | None = None,
|
|
491
467
|
) -> tuple[bool, dict[str, Any] | str]:
|
|
492
|
-
mtoken =
|
|
493
|
-
account =
|
|
468
|
+
mtoken = to_checksum_address(mtoken)
|
|
469
|
+
account = (
|
|
470
|
+
to_checksum_address(account) if account else self.strategy_wallet_address
|
|
471
|
+
)
|
|
494
472
|
block_id = block_identifier if block_identifier is not None else "pending"
|
|
495
473
|
|
|
496
474
|
bal = exch = borrow = underlying = rewards = None
|
|
@@ -615,7 +593,7 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
615
593
|
mtoken: str,
|
|
616
594
|
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
617
595
|
) -> tuple[bool, float | str]:
|
|
618
|
-
mtoken =
|
|
596
|
+
mtoken = to_checksum_address(mtoken)
|
|
619
597
|
|
|
620
598
|
now = time.time()
|
|
621
599
|
if mtoken in self._cf_cache:
|
|
@@ -664,7 +642,7 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
664
642
|
include_rewards: bool = True,
|
|
665
643
|
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
666
644
|
) -> tuple[bool, float | str]:
|
|
667
|
-
mtoken =
|
|
645
|
+
mtoken = to_checksum_address(mtoken)
|
|
668
646
|
|
|
669
647
|
last_error = ""
|
|
670
648
|
for attempt in range(max_retries):
|
|
@@ -811,7 +789,9 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
811
789
|
account: str | None = None,
|
|
812
790
|
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
813
791
|
) -> tuple[bool, int | str]:
|
|
814
|
-
account =
|
|
792
|
+
account = (
|
|
793
|
+
to_checksum_address(account) if account else self.strategy_wallet_address
|
|
794
|
+
)
|
|
815
795
|
|
|
816
796
|
last_error = ""
|
|
817
797
|
for attempt in range(max_retries):
|
|
@@ -852,8 +832,10 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
852
832
|
mtoken: str,
|
|
853
833
|
account: str | None = None,
|
|
854
834
|
) -> tuple[bool, dict[str, Any] | str]:
|
|
855
|
-
mtoken =
|
|
856
|
-
account =
|
|
835
|
+
mtoken = to_checksum_address(mtoken)
|
|
836
|
+
account = (
|
|
837
|
+
to_checksum_address(account) if account else self.strategy_wallet_address
|
|
838
|
+
)
|
|
857
839
|
|
|
858
840
|
try:
|
|
859
841
|
async with web3_from_chain_id(self.chain_id) as web3:
|
|
@@ -949,16 +931,12 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
949
931
|
except Exception as exc:
|
|
950
932
|
return False, str(exc)
|
|
951
933
|
|
|
952
|
-
# ------------------------------------------------------------------ #
|
|
953
|
-
# Public API - ETH Wrapping #
|
|
954
|
-
# ------------------------------------------------------------------ #
|
|
955
|
-
|
|
956
934
|
async def wrap_eth(
|
|
957
935
|
self,
|
|
958
936
|
*,
|
|
959
937
|
amount: int,
|
|
960
938
|
) -> tuple[bool, Any]:
|
|
961
|
-
strategy = self.
|
|
939
|
+
strategy = self.strategy_wallet_address
|
|
962
940
|
amount = int(amount)
|
|
963
941
|
if amount <= 0:
|
|
964
942
|
return False, "amount must be positive"
|
|
@@ -971,57 +949,8 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
971
949
|
from_address=strategy,
|
|
972
950
|
value=amount,
|
|
973
951
|
)
|
|
974
|
-
return await self._send_tx(tx)
|
|
975
|
-
|
|
976
|
-
# ------------------------------------------------------------------ #
|
|
977
|
-
# Helpers #
|
|
978
|
-
# ------------------------------------------------------------------ #
|
|
979
|
-
|
|
980
|
-
# Max uint256 for unlimited approvals
|
|
981
|
-
MAX_UINT256 = 2**256 - 1
|
|
982
|
-
|
|
983
|
-
async def _send_tx(self, tx: dict[str, Any]) -> tuple[bool, Any]:
|
|
984
952
|
txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
|
|
985
|
-
return True, txn_hash
|
|
986
|
-
|
|
987
|
-
async def _ensure_allowance(
|
|
988
|
-
self,
|
|
989
|
-
*,
|
|
990
|
-
token_address: str,
|
|
991
|
-
owner: str,
|
|
992
|
-
spender: str,
|
|
993
|
-
amount: int,
|
|
994
|
-
) -> tuple[bool, Any]:
|
|
995
|
-
allowance = await get_token_allowance(
|
|
996
|
-
token_address, self.chain_id, owner, spender
|
|
997
|
-
)
|
|
998
|
-
if allowance >= amount:
|
|
999
|
-
return True, {}
|
|
1000
|
-
|
|
1001
|
-
# Approve for max uint256 to avoid precision/timing issues
|
|
1002
|
-
approve_tx = await build_approve_transaction(
|
|
1003
|
-
from_address=owner,
|
|
1004
|
-
chain_id=self.chain_id,
|
|
1005
|
-
token_address=token_address,
|
|
1006
|
-
spender_address=spender,
|
|
1007
|
-
amount=self.MAX_UINT256,
|
|
1008
|
-
)
|
|
1009
|
-
|
|
1010
|
-
result = await self._send_tx(approve_tx)
|
|
1011
|
-
|
|
1012
|
-
# Small delay after approval to ensure state is propagated on providers/chains
|
|
1013
|
-
# where we don't wait for additional confirmations by default.
|
|
1014
|
-
if result[0]:
|
|
1015
|
-
confirmations = 0
|
|
1016
|
-
if isinstance(result[1], dict):
|
|
1017
|
-
try:
|
|
1018
|
-
confirmations = int(result[1].get("confirmations") or 0)
|
|
1019
|
-
except (TypeError, ValueError):
|
|
1020
|
-
confirmations = 0
|
|
1021
|
-
if confirmations == 0:
|
|
1022
|
-
await asyncio.sleep(1.0)
|
|
1023
|
-
|
|
1024
|
-
return result
|
|
953
|
+
return (True, txn_hash)
|
|
1025
954
|
|
|
1026
955
|
async def _encode_call(
|
|
1027
956
|
self,
|
|
@@ -1052,22 +981,3 @@ class MoonwellAdapter(BaseAdapter):
|
|
|
1052
981
|
"value": int(value),
|
|
1053
982
|
}
|
|
1054
983
|
return tx
|
|
1055
|
-
|
|
1056
|
-
def _strategy_address(self) -> str:
|
|
1057
|
-
addr = None
|
|
1058
|
-
if isinstance(self.strategy_wallet, dict):
|
|
1059
|
-
addr = self.strategy_wallet.get("address") or (
|
|
1060
|
-
(self.strategy_wallet.get("evm") or {}).get("address")
|
|
1061
|
-
)
|
|
1062
|
-
elif isinstance(self.strategy_wallet, str):
|
|
1063
|
-
addr = self.strategy_wallet
|
|
1064
|
-
if not addr:
|
|
1065
|
-
raise ValueError(
|
|
1066
|
-
"strategy_wallet address is required for Moonwell operations"
|
|
1067
|
-
)
|
|
1068
|
-
return to_checksum_address(addr)
|
|
1069
|
-
|
|
1070
|
-
def _checksum(self, address: str | None) -> str:
|
|
1071
|
-
if not address:
|
|
1072
|
-
raise ValueError("Missing required contract address in Moonwell config")
|
|
1073
|
-
return to_checksum_address(address)
|