You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

vana

Package Overview
Dependencies
Maintainers
1
Versions
50
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

vana - pypi Package Compare versions

Comparing version
0.39.0
to
0.40.0
+1
-1
PKG-INFO
Metadata-Version: 2.1
Name: vana
Version: 0.39.0
Version: 0.40.0
Summary:

@@ -5,0 +5,0 @@ Home-page: https://github.com/vana-com/vana-framework

[tool.poetry]
name = "vana"
version = "0.39.0"
version = "0.40.0"
description = ""

@@ -5,0 +5,0 @@ authors = ["Tim Nunamaker <tim@vana.com>", "Volodymyr Isai <volod@vana.com>", "Kahtaf Alam <kahtaf@vana.com>"]

@@ -18,3 +18,3 @@ # The MIT License (MIT)

__version__ = "0.39.0"
__version__ = "0.40.0"

@@ -21,0 +21,0 @@ import rich

@@ -16,56 +16,5 @@ from threading import Lock

self.account = account
self._nonce_cache: Dict[str, int] = {}
self._last_nonce_refresh = 0
self.nonce_refresh_interval = 60
self._nonce_lock = Lock()
self.chain_id = self.web3.eth.chain_id
self._nonce_lock = Lock()
def _get_safe_nonce(self) -> Nonce:
"""
Get the next safe nonce, accounting for pending transactions.
Thread-safe implementation for concurrent transaction submissions.
Returns:
Nonce: Next safe nonce to use for transaction
"""
with self._nonce_lock:
current_time = time.time()
cache_key = self.account.address
should_refresh = (
current_time - self._last_nonce_refresh > self.nonce_refresh_interval or
cache_key not in self._nonce_cache
)
if should_refresh:
try:
# Get both confirmed and pending nonces
confirmed_nonce: Nonce = self.web3.eth.get_transaction_count(self.account.address, 'latest')
pending_nonce: Nonce = self.web3.eth.get_transaction_count(self.account.address, 'pending')
# Use max to account for pending transactions
new_nonce: Nonce = Nonce(max(int(confirmed_nonce), int(pending_nonce)))
# Only update if new nonce is higher than cached
cached_nonce: Nonce = Nonce(self._nonce_cache.get(cache_key, 0))
self._nonce_cache[cache_key] = Nonce(max(int(new_nonce), int(cached_nonce)))
self._last_nonce_refresh = current_time
vana.logging.debug(
f"Nonce cache refreshed - Latest: {confirmed_nonce}, "
f"Pending: {pending_nonce}, "
f"Using: {self._nonce_cache[cache_key]}"
)
except Exception as e:
vana.logging.error(f"Error refreshing nonce: {str(e)}")
if cache_key not in self._nonce_cache:
raise
# Get and increment the cached nonce atomically
nonce = self._nonce_cache[cache_key]
self._nonce_cache[cache_key] = Nonce(int(nonce) + 1)
return nonce
def _clear_pending_transactions(self, max_wait_time: int = 180):

@@ -150,3 +99,3 @@ """

timeout: int = 30,
clear_pending_transactions: bool = True
clear_pending_transactions: bool = False
) -> Tuple[HexBytes, TxReceipt]:

@@ -164,3 +113,2 @@ """

base_gas_multiplier: Base multiplier for gas price on retries (default: 1.5)
max_gas_multiplier: Maximum allowed gas price multiplier (default: 5.0)
timeout: Timeout in seconds to wait for transaction receipt (default: 30)

@@ -189,51 +137,55 @@ clear_pending_transactions: Attempt to clear pending transactions before sending (default: False)

try:
# Estimate gas with conservative buffer
gas_estimate = function.estimate_gas({
'from': account.address,
'value': value,
'chainId': self.chain_id
})
gas_limit = int(gas_estimate * 2)
with self._nonce_lock:
# Get nonce directly from chain within lock
nonce = self.web3.eth.get_transaction_count(self.account.address, 'pending')
# Calculate gas price - use base price for first attempt
base_gas_price = self.web3.eth.gas_price
gas_multiplier = base_gas_multiplier * (1.5 ** retry_count)
gas_price = int(base_gas_price * gas_multiplier)
# Estimate gas with conservative buffer
gas_estimate = function.estimate_gas({
'from': account.address,
'value': value,
'chainId': self.chain_id,
'nonce': nonce
})
gas_limit = int(gas_estimate * 2)
# Get safe nonce and build transaction
nonce = self._get_safe_nonce()
tx = function.build_transaction({
'from': account.address,
'value': value,
'gas': gas_limit,
'gasPrice': gas_price,
'nonce': nonce,
'chainId': self.chain_id
})
# Calculate gas price - use base price for first attempt
base_gas_price = self.web3.eth.gas_price
gas_multiplier = base_gas_multiplier * (1.5 ** retry_count)
gas_price = int(base_gas_price * gas_multiplier)
try:
# Simulate transaction first to catch reverts
self.web3.eth.call({
'from': tx['from'],
'to': tx['to'],
'data': tx['data'],
'value': tx['value'],
'gas': tx['gas'],
'gasPrice': tx['gasPrice'],
# Build transaction
tx = function.build_transaction({
'from': account.address,
'value': value,
'gas': gas_limit,
'gasPrice': gas_price,
'nonce': nonce,
'chainId': self.chain_id
})
except ContractLogicError as e:
vana.logging.error(f"Transaction would revert: {str(e)}")
raise Exception(f"Transaction would revert: {str(e)}")
signed_tx = self.web3.eth.account.sign_transaction(tx, account.key)
try:
# Simulate transaction first to catch reverts
self.web3.eth.call({
'from': tx['from'],
'to': tx['to'],
'data': tx['data'],
'value': tx['value'],
'gas': tx['gas'],
'gasPrice': tx['gasPrice'],
})
except ContractLogicError as e:
vana.logging.error(f"Transaction would revert: {str(e)}")
raise Exception(f"Transaction would revert: {str(e)}")
vana.logging.info(
f"Sending transaction with nonce {nonce}, "
f"gas price {gas_price} ({gas_multiplier:.1f}x base) "
f"(retry {retry_count})"
)
signed_tx = self.web3.eth.account.sign_transaction(tx, account.key)
tx_hash = self.web3.eth.send_raw_transaction(signed_tx.rawTransaction)
vana.logging.info(
f"Sending transaction with nonce {nonce}, "
f"gas price {gas_price} ({gas_multiplier:.1f}x base) "
f"(retry {retry_count})"
)
# Wait for receipt with timeout
tx_hash = self.web3.eth.send_raw_transaction(signed_tx.rawTransaction)
# Wait for receipt outside the lock since transaction is already submitted
start_time = time.time()

@@ -240,0 +192,0 @@ while True: