golem-vm-provider 0.1.51__tar.gz → 0.1.53__tar.gz
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.
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/PKG-INFO +3 -1
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/README.md +2 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/main.py +166 -39
- golem_vm_provider-0.1.53/provider/security/l2_faucet.py +63 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/utils/pricing.py +8 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/pyproject.toml +1 -1
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/__init__.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/api/__init__.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/api/models.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/api/routes.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/config.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/container.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/data/deployments/l2.json +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/__init__.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/advertiser.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/golem_base_advertiser.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/golem_base_utils.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/multi_advertiser.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/resource_monitor.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/resource_tracker.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/service.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/network/port_verifier.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/payments/blockchain_service.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/payments/monitor.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/payments/stream_map.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/security/ethereum.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/security/faucet.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/service.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/utils/__init__.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/utils/ascii_art.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/utils/logging.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/utils/port_display.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/utils/retry.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/utils/setup.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/vm/__init__.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/vm/cloud_init.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/vm/models.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/vm/multipass.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/vm/multipass_adapter.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/vm/name_mapper.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/vm/port_manager.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/vm/provider.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/vm/proxy_manager.py +0 -0
- {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/vm/service.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: golem-vm-provider
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.53
|
4
4
|
Summary: VM on Golem Provider Node - Run your own provider node to offer VMs on the Golem Network
|
5
5
|
Keywords: golem,vm,provider,cloud,decentralized
|
6
6
|
Author: Phillip Jensen
|
@@ -454,6 +454,8 @@ poetry run golem-provider streams withdraw --vm-id <vm_id>
|
|
454
454
|
poetry run golem-provider streams withdraw --all
|
455
455
|
```
|
456
456
|
|
457
|
+
Note: On testnets, the withdraw command auto-attempts to fund the provider's L2 address via the configured faucet if native gas balance is low.
|
458
|
+
|
457
459
|
Configure monitor and withdraw via CLI:
|
458
460
|
|
459
461
|
```bash
|
@@ -409,6 +409,8 @@ poetry run golem-provider streams withdraw --vm-id <vm_id>
|
|
409
409
|
poetry run golem-provider streams withdraw --all
|
410
410
|
```
|
411
411
|
|
412
|
+
Note: On testnets, the withdraw command auto-attempts to fund the provider's L2 address via the configured faucet if native gas balance is low.
|
413
|
+
|
412
414
|
Configure monitor and withdraw via CLI:
|
413
415
|
|
414
416
|
```bash
|
@@ -147,38 +147,17 @@ def main():
|
|
147
147
|
def wallet_faucet_l2():
|
148
148
|
"""Request L2 faucet funds for the provider's payment address (native ETH)."""
|
149
149
|
from .config import settings
|
150
|
-
from
|
151
|
-
from web3 import Web3
|
150
|
+
from .security.l2_faucet import L2FaucetService
|
152
151
|
try:
|
153
152
|
addr = settings.PROVIDER_ID
|
154
|
-
faucet = PowFaucetClient(settings.L2_FAUCET_URL, settings.L2_CAPTCHA_URL, settings.L2_CAPTCHA_API_KEY)
|
155
|
-
# Check current L2 balance
|
156
|
-
w3 = Web3(Web3.HTTPProvider(settings.POLYGON_RPC_URL))
|
157
|
-
bal = 0.0
|
158
|
-
try:
|
159
|
-
bal = float(w3.from_wei(w3.eth.get_balance(Web3.to_checksum_address(addr)), 'ether'))
|
160
|
-
except Exception:
|
161
|
-
pass
|
162
|
-
if bal > 0.01:
|
163
|
-
print(f"Sufficient L2 funds ({bal} ETH); skipping faucet.")
|
164
|
-
return
|
165
153
|
async def _run():
|
166
|
-
|
167
|
-
|
168
|
-
print("Failed to get challenge")
|
169
|
-
raise typer.Exit(code=1)
|
170
|
-
sols = []
|
171
|
-
for salt, target in chall.get('challenge') or []:
|
172
|
-
sols.append((salt, target, PowFaucetClient.solve_challenge(salt, target)))
|
173
|
-
redeemed = await faucet.redeem(chall.get('token'), sols)
|
174
|
-
if not redeemed:
|
175
|
-
print("Failed to redeem solutions")
|
176
|
-
raise typer.Exit(code=1)
|
177
|
-
tx = await faucet.request_funds(addr, redeemed)
|
154
|
+
svc = L2FaucetService(settings)
|
155
|
+
tx = await svc.request_funds(addr)
|
178
156
|
if tx:
|
179
157
|
print(f"Faucet tx: {tx}")
|
180
158
|
else:
|
181
|
-
|
159
|
+
# Either skipped due to sufficient balance or failed
|
160
|
+
pass
|
182
161
|
asyncio.run(_run())
|
183
162
|
except Exception as e:
|
184
163
|
print(f"Error: {e}")
|
@@ -191,6 +170,9 @@ def streams_list(json_out: bool = typer.Option(False, "--json", help="Output in
|
|
191
170
|
from .container import Container
|
192
171
|
from .config import settings
|
193
172
|
from .payments.blockchain_service import StreamPaymentReader
|
173
|
+
from .utils.pricing import fetch_glm_usd_price, fetch_eth_usd_price
|
174
|
+
from decimal import Decimal
|
175
|
+
from web3 import Web3
|
194
176
|
import json as _json
|
195
177
|
try:
|
196
178
|
if not settings.STREAM_PAYMENT_ADDRESS or settings.STREAM_PAYMENT_ADDRESS == "0x0000000000000000000000000000000000000000":
|
@@ -213,6 +195,7 @@ def streams_list(json_out: bool = typer.Option(False, "--json", help="Output in
|
|
213
195
|
rows.append({
|
214
196
|
"vm_id": vm_id,
|
215
197
|
"stream_id": int(stream_id),
|
198
|
+
"token": str(s.get("token")),
|
216
199
|
"recipient": s["recipient"],
|
217
200
|
"start": int(s["startTime"]),
|
218
201
|
"stop": int(s["stopTime"]),
|
@@ -232,12 +215,66 @@ def streams_list(json_out: bool = typer.Option(False, "--json", help="Output in
|
|
232
215
|
if not rows:
|
233
216
|
print("No streams mapped.")
|
234
217
|
return
|
235
|
-
|
218
|
+
# Prepare human-friendly display (ETH/GLM + USD)
|
219
|
+
ZERO = "0x0000000000000000000000000000000000000000"
|
220
|
+
# Cache prices so we don't query per-row
|
221
|
+
price_cache: dict[str, Optional[Decimal]] = {"ETH": None, "GLM": None}
|
222
|
+
# Determine which symbols are present
|
223
|
+
symbols_present = set()
|
236
224
|
for r in rows:
|
237
225
|
if "error" in r:
|
238
|
-
|
239
|
-
|
240
|
-
|
226
|
+
continue
|
227
|
+
token_addr = (r.get("token") or "").lower()
|
228
|
+
sym = "ETH" if token_addr == ZERO.lower() else "GLM"
|
229
|
+
symbols_present.add(sym)
|
230
|
+
if "ETH" in symbols_present:
|
231
|
+
price_cache["ETH"] = fetch_eth_usd_price()
|
232
|
+
if "GLM" in symbols_present:
|
233
|
+
price_cache["GLM"] = fetch_glm_usd_price()
|
234
|
+
|
235
|
+
# Build table rows
|
236
|
+
table_rows = []
|
237
|
+
for r in rows:
|
238
|
+
if "error" in r:
|
239
|
+
table_rows.append([r["vm_id"], str(r["stream_id"]), "—", "ERROR", r.get("error", ""), "—"])
|
240
|
+
continue
|
241
|
+
token_addr = (r.get("token") or "").lower()
|
242
|
+
sym = "ETH" if token_addr == ZERO.lower() else "GLM"
|
243
|
+
withdrawable_eth = Decimal(str(Web3.from_wei(int(r["withdrawable"]), "ether")))
|
244
|
+
withdrawable_str = f"{withdrawable_eth:.6f} {sym}"
|
245
|
+
price = price_cache.get(sym)
|
246
|
+
usd_str = "—"
|
247
|
+
if price is not None:
|
248
|
+
try:
|
249
|
+
usd_val = (withdrawable_eth * price).quantize(Decimal("0.01"))
|
250
|
+
usd_str = f"${usd_val}"
|
251
|
+
except Exception:
|
252
|
+
usd_str = "—"
|
253
|
+
table_rows.append([
|
254
|
+
r["vm_id"],
|
255
|
+
str(r["stream_id"]),
|
256
|
+
f"{int(r['remaining'])}s",
|
257
|
+
"yes" if r["verified"] else "no",
|
258
|
+
withdrawable_str,
|
259
|
+
usd_str,
|
260
|
+
])
|
261
|
+
|
262
|
+
headers = ["VM", "Stream", "Remaining", "Verified", "Withdrawable", "USD"]
|
263
|
+
# Compute column widths
|
264
|
+
cols = len(headers)
|
265
|
+
col_widths = [len(h) for h in headers]
|
266
|
+
for row in table_rows:
|
267
|
+
for i in range(cols):
|
268
|
+
col_widths[i] = max(col_widths[i], len(str(row[i])))
|
269
|
+
|
270
|
+
def fmt_row(values: list[str]) -> str:
|
271
|
+
return " ".join(str(values[i]).ljust(col_widths[i]) for i in range(cols))
|
272
|
+
|
273
|
+
print("\nStreams")
|
274
|
+
print(fmt_row(headers))
|
275
|
+
print(" ".join("-" * w for w in col_widths))
|
276
|
+
for row in table_rows:
|
277
|
+
print(fmt_row(row))
|
241
278
|
except Exception as e:
|
242
279
|
print(f"Error: {e}")
|
243
280
|
raise typer.Exit(code=1)
|
@@ -249,6 +286,9 @@ def streams_show(vm_id: str = typer.Argument(..., help="VM id (requestor_name)")
|
|
249
286
|
from .container import Container
|
250
287
|
from .config import settings
|
251
288
|
from .payments.blockchain_service import StreamPaymentReader
|
289
|
+
from .utils.pricing import fetch_glm_usd_price, fetch_eth_usd_price
|
290
|
+
from decimal import Decimal
|
291
|
+
from web3 import Web3
|
252
292
|
import json as _json
|
253
293
|
try:
|
254
294
|
c = Container()
|
@@ -281,7 +321,43 @@ def streams_show(vm_id: str = typer.Argument(..., help="VM id (requestor_name)")
|
|
281
321
|
if json_out:
|
282
322
|
print(_json.dumps(out, indent=2))
|
283
323
|
else:
|
284
|
-
|
324
|
+
ZERO = "0x0000000000000000000000000000000000000000"
|
325
|
+
token_addr = (s.get("token") or "").lower()
|
326
|
+
sym = "ETH" if token_addr == ZERO.lower() else "GLM"
|
327
|
+
nat = Decimal(str(Web3.from_wei(int(withdrawable), "ether")))
|
328
|
+
price = fetch_eth_usd_price() if sym == "ETH" else fetch_glm_usd_price()
|
329
|
+
usd_str = "—"
|
330
|
+
if price is not None:
|
331
|
+
try:
|
332
|
+
usd_val = (nat * price).quantize(Decimal("0.01"))
|
333
|
+
usd_str = f"${usd_val}"
|
334
|
+
except Exception:
|
335
|
+
usd_str = "—"
|
336
|
+
def _fmt_seconds(sec: int) -> str:
|
337
|
+
m, s2 = divmod(int(sec), 60)
|
338
|
+
h, m = divmod(m, 60)
|
339
|
+
d, h = divmod(h, 24)
|
340
|
+
parts = []
|
341
|
+
if d: parts.append(f"{d}d")
|
342
|
+
if h: parts.append(f"{h}h")
|
343
|
+
if m and not d: parts.append(f"{m}m")
|
344
|
+
if s2 and not d and not h and not m: parts.append(f"{s2}s")
|
345
|
+
return " ".join(parts) or "0s"
|
346
|
+
# Pretty single-record display
|
347
|
+
print("\nStream Details")
|
348
|
+
headers = ["VM", "Stream", "Remaining", "Verified", "Withdrawable", "USD"]
|
349
|
+
cols = [
|
350
|
+
vm_id,
|
351
|
+
str(sid),
|
352
|
+
_fmt_seconds(remaining),
|
353
|
+
"yes" if ok else "no",
|
354
|
+
f"{nat:.6f} {sym}",
|
355
|
+
usd_str,
|
356
|
+
]
|
357
|
+
w = [max(len(headers[i]), len(str(cols[i]))) for i in range(len(headers))]
|
358
|
+
print(" ".join(headers[i].ljust(w[i]) for i in range(len(w))))
|
359
|
+
print(" ".join("-" * wi for wi in w))
|
360
|
+
print(" ".join(str(cols[i]).ljust(w[i]) for i in range(len(w))))
|
285
361
|
except Exception as e:
|
286
362
|
print(f"Error: {e}")
|
287
363
|
raise typer.Exit(code=1)
|
@@ -292,6 +368,9 @@ def streams_earnings(json_out: bool = typer.Option(False, "--json", help="Output
|
|
292
368
|
from .container import Container
|
293
369
|
from .config import settings
|
294
370
|
from .payments.blockchain_service import StreamPaymentReader
|
371
|
+
from .utils.pricing import fetch_glm_usd_price, fetch_eth_usd_price
|
372
|
+
from decimal import Decimal
|
373
|
+
from web3 import Web3
|
295
374
|
import json as _json
|
296
375
|
try:
|
297
376
|
c = Container()
|
@@ -304,6 +383,8 @@ def streams_earnings(json_out: bool = typer.Option(False, "--json", help="Output
|
|
304
383
|
total_vested = 0
|
305
384
|
total_withdrawn = 0
|
306
385
|
total_withdrawable = 0
|
386
|
+
ZERO = "0x0000000000000000000000000000000000000000"
|
387
|
+
sums_native: dict[str, Decimal] = {"ETH": Decimal("0"), "GLM": Decimal("0")}
|
307
388
|
for vm_id, stream_id in items.items():
|
308
389
|
try:
|
309
390
|
s = reader.get_stream(int(stream_id))
|
@@ -312,9 +393,12 @@ def streams_earnings(json_out: bool = typer.Option(False, "--json", help="Output
|
|
312
393
|
total_vested += int(vested)
|
313
394
|
total_withdrawn += int(s["withdrawn"]) # type: ignore
|
314
395
|
total_withdrawable += int(withdrawable)
|
396
|
+
sym = "ETH" if (s.get("token") or "").lower() == ZERO.lower() else "GLM"
|
397
|
+
sums_native[sym] += Decimal(str(Web3.from_wei(int(withdrawable), "ether")))
|
315
398
|
rows.append({
|
316
399
|
"vm_id": vm_id,
|
317
400
|
"stream_id": int(stream_id),
|
401
|
+
"token": str(s.get("token")),
|
318
402
|
"vested": int(vested),
|
319
403
|
"withdrawn": int(s["withdrawn"]),
|
320
404
|
"withdrawable": int(withdrawable),
|
@@ -332,17 +416,53 @@ def streams_earnings(json_out: bool = typer.Option(False, "--json", help="Output
|
|
332
416
|
if json_out:
|
333
417
|
print(_json.dumps(out, indent=2))
|
334
418
|
return
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
419
|
+
# Human summary by token with USD
|
420
|
+
price_eth = fetch_eth_usd_price()
|
421
|
+
price_glm = fetch_glm_usd_price()
|
422
|
+
def _fmt_usd(amount_native: Decimal, price: Optional[Decimal]) -> str:
|
423
|
+
if price is None:
|
424
|
+
return "—"
|
425
|
+
try:
|
426
|
+
return f"${(amount_native * price).quantize(Decimal('0.01'))}"
|
427
|
+
except Exception:
|
428
|
+
return "—"
|
429
|
+
print("\nEarnings Summary")
|
430
|
+
headers = ["Token", "Withdrawable", "USD"]
|
431
|
+
data_rows = [
|
432
|
+
["ETH", f"{sums_native['ETH']:.6f} ETH", _fmt_usd(sums_native["ETH"], price_eth)],
|
433
|
+
["GLM", f"{sums_native['GLM']:.6f} GLM", _fmt_usd(sums_native["GLM"], price_glm)],
|
434
|
+
]
|
435
|
+
# Table widths
|
436
|
+
w = [len(h) for h in headers]
|
437
|
+
for r in data_rows:
|
438
|
+
for i in range(3):
|
439
|
+
w[i] = max(w[i], len(str(r[i])))
|
440
|
+
print(" ".join(headers[i].ljust(w[i]) for i in range(3)))
|
441
|
+
print(" ".join("-" * wi for wi in w))
|
442
|
+
for r in data_rows:
|
443
|
+
print(" ".join(str(r[i]).ljust(w[i]) for i in range(3)))
|
444
|
+
# Per stream table
|
339
445
|
if rows:
|
340
|
-
|
446
|
+
table = []
|
341
447
|
for r in rows:
|
342
448
|
if "error" in r:
|
343
|
-
|
344
|
-
|
345
|
-
|
449
|
+
table.append([r["vm_id"], str(r["stream_id"]), "ERROR", r.get("error", "")])
|
450
|
+
continue
|
451
|
+
sym = "ETH" if (r.get("token") or "").lower() == ZERO.lower() else "GLM"
|
452
|
+
nat = Decimal(str(Web3.from_wei(int(r["withdrawable"]), "ether")))
|
453
|
+
price = price_eth if sym == "ETH" else price_glm
|
454
|
+
usd = _fmt_usd(nat, price)
|
455
|
+
table.append([r["vm_id"], str(r["stream_id"]), f"{nat:.6f} {sym}", usd])
|
456
|
+
h2 = ["VM", "Stream", "Withdrawable", "USD"]
|
457
|
+
w2 = [len(x) for x in h2]
|
458
|
+
for row in table:
|
459
|
+
for i in range(4):
|
460
|
+
w2[i] = max(w2[i], len(str(row[i])))
|
461
|
+
print("\nPer Stream")
|
462
|
+
print(" ".join(h2[i].ljust(w2[i]) for i in range(4)))
|
463
|
+
print(" ".join("-" * wi for wi in w2))
|
464
|
+
for row in table:
|
465
|
+
print(" ".join(str(row[i]).ljust(w2[i]) for i in range(4)))
|
346
466
|
except Exception as e:
|
347
467
|
print(f"Error: {e}")
|
348
468
|
raise typer.Exit(code=1)
|
@@ -356,6 +476,7 @@ def streams_withdraw(
|
|
356
476
|
"""Withdraw vested funds for one or all streams."""
|
357
477
|
from .container import Container
|
358
478
|
from .config import settings
|
479
|
+
from .security.l2_faucet import L2FaucetService
|
359
480
|
try:
|
360
481
|
if not vm_id and not all_streams:
|
361
482
|
print("Specify --vm-id or --all")
|
@@ -364,6 +485,12 @@ def streams_withdraw(
|
|
364
485
|
c.config.from_pydantic(settings)
|
365
486
|
stream_map = c.stream_map()
|
366
487
|
client = c.stream_client()
|
488
|
+
# Ensure we have L2 gas for withdrawals (testnets)
|
489
|
+
try:
|
490
|
+
asyncio.run(L2FaucetService(settings).request_funds(settings.PROVIDER_ID))
|
491
|
+
except Exception:
|
492
|
+
# Non-fatal; proceed with withdraw attempt
|
493
|
+
pass
|
367
494
|
targets = []
|
368
495
|
if all_streams:
|
369
496
|
items = asyncio.run(stream_map.all_items())
|
@@ -0,0 +1,63 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import Optional, List, Tuple
|
4
|
+
|
5
|
+
from web3 import Web3
|
6
|
+
from golem_faucet import PowFaucetClient
|
7
|
+
from ..utils.logging import setup_logger
|
8
|
+
|
9
|
+
logger = setup_logger(__name__)
|
10
|
+
|
11
|
+
|
12
|
+
class L2FaucetService:
|
13
|
+
"""Request native ETH on the L2 payments chain via PoW faucet.
|
14
|
+
|
15
|
+
Uses provider settings for RPC and faucet endpoints.
|
16
|
+
"""
|
17
|
+
|
18
|
+
def __init__(self, config):
|
19
|
+
# Config is expected to expose POLYGON_RPC_URL, L2_* faucet fields
|
20
|
+
self.cfg = config
|
21
|
+
self.web3 = Web3(Web3.HTTPProvider(config.POLYGON_RPC_URL))
|
22
|
+
self.client = PowFaucetClient(
|
23
|
+
faucet_url=getattr(config, "L2_FAUCET_URL", "https://l2.holesky.golemdb.io/faucet"),
|
24
|
+
captcha_base_url=getattr(config, "L2_CAPTCHA_URL", "https://cap.gobas.me"),
|
25
|
+
captcha_api_key=getattr(config, "L2_CAPTCHA_API_KEY", "05381a2cef5e"),
|
26
|
+
)
|
27
|
+
|
28
|
+
def _balance_eth(self, address: str) -> float:
|
29
|
+
try:
|
30
|
+
wei = self.web3.eth.get_balance(Web3.to_checksum_address(address))
|
31
|
+
return float(self.web3.from_wei(wei, "ether"))
|
32
|
+
except Exception as e:
|
33
|
+
logger.warning(f"L2 balance check failed: {e}")
|
34
|
+
return 0.0
|
35
|
+
|
36
|
+
async def request_funds(self, address: str) -> Optional[str]:
|
37
|
+
"""Ensure some native ETH on L2; if low, solve PoW and request faucet payout.
|
38
|
+
|
39
|
+
Returns tx hash string on payout, or None if skipped/failed.
|
40
|
+
"""
|
41
|
+
bal = self._balance_eth(address)
|
42
|
+
if bal > 0.01:
|
43
|
+
logger.info(f"Sufficient L2 funds ({bal} ETH), skipping faucet.")
|
44
|
+
return None
|
45
|
+
chall = await self.client.get_challenge()
|
46
|
+
if not chall:
|
47
|
+
logger.error("could not fetch faucet challenge")
|
48
|
+
return None
|
49
|
+
token = chall.get("token")
|
50
|
+
challenge_list = chall.get("challenge") or []
|
51
|
+
solutions: List[Tuple[str, str, int]] = []
|
52
|
+
for salt, target in challenge_list:
|
53
|
+
nonce = PowFaucetClient.solve_challenge(salt, target)
|
54
|
+
solutions.append((salt, target, nonce))
|
55
|
+
redeemed = await self.client.redeem(token, solutions)
|
56
|
+
if not redeemed:
|
57
|
+
logger.error("failed to redeem challenge")
|
58
|
+
return None
|
59
|
+
tx = await self.client.request_funds(address, redeemed)
|
60
|
+
if tx:
|
61
|
+
logger.success(f"L2 faucet sent tx: {tx}")
|
62
|
+
return tx
|
63
|
+
|
@@ -47,6 +47,14 @@ def fetch_glm_usd_price() -> Optional[Decimal]:
|
|
47
47
|
return _coingecko_simple_price(settings.COINGECKO_IDS)
|
48
48
|
|
49
49
|
|
50
|
+
def fetch_eth_usd_price() -> Optional[Decimal]:
|
51
|
+
"""Fetch the current ETH price in USD from CoinGecko.
|
52
|
+
|
53
|
+
Uses the canonical "ethereum" id.
|
54
|
+
"""
|
55
|
+
return _coingecko_simple_price("ethereum")
|
56
|
+
|
57
|
+
|
50
58
|
def usd_to_glm(usd_amount: Decimal, glm_usd: Decimal) -> Decimal:
|
51
59
|
if glm_usd <= 0:
|
52
60
|
raise ValueError("Invalid GLM/USD price")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "golem-vm-provider"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.53"
|
4
4
|
description = "VM on Golem Provider Node - Run your own provider node to offer VMs on the Golem Network"
|
5
5
|
authors = ["Phillip Jensen <phillip+vm-on-golem@golemgrid.com>"]
|
6
6
|
readme = "README.md"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/golem_base_advertiser.py
RENAMED
File without changes
|
{golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/golem_base_utils.py
RENAMED
File without changes
|
{golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/multi_advertiser.py
RENAMED
File without changes
|
{golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/resource_monitor.py
RENAMED
File without changes
|
{golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/discovery/resource_tracker.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{golem_vm_provider-0.1.51 → golem_vm_provider-0.1.53}/provider/payments/blockchain_service.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|