diff --git a/CHANGELOG.md b/CHANGELOG.md index e3274418..2bbb6c29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ -# Current +# 0.22.24 + +- Internal change: more verbose logging for `wait_and_broadcast_multiple_nodes` + +# 0.22.23 - API change: add `fetch_erc20_balances_by_token_list(block_identifier)` diff --git a/contracts/in-house/README.md b/contracts/in-house/README.md index ddd68eb0..ea690553 100644 --- a/contracts/in-house/README.md +++ b/contracts/in-house/README.md @@ -8,6 +8,10 @@ It's unlikely you want to use any of these contracts directly. ## Compile ```shell +# Need to fetch OpenZeppelin version we depend on +(cd contracts/enzyme && pnpm install) + +# Proceed with our own project cd contracts/in-house forge build ``` @@ -30,7 +34,10 @@ and gasless transactions. - Then deploy the USDC payment relay ```shell -# Address of deployed vault comptroller +# Address of deployed vault comptroller contract for the vault contract +# +# You can get this from vault.getAccessor() call +# export VAULT_COMPTROLLER= # Deployer account diff --git a/contracts/in-house/src/VaultUSDCPaymentForwarder.sol b/contracts/in-house/src/VaultUSDCPaymentForwarder.sol index 4c8e7979..8ed7368d 100644 --- a/contracts/in-house/src/VaultUSDCPaymentForwarder.sol +++ b/contracts/in-house/src/VaultUSDCPaymentForwarder.sol @@ -34,6 +34,9 @@ contract VaultUSDCPaymentForwarder { IEIP3009 public token; // The comptroller of the vault for which we are buying shares + // + // You can get this from vault by asking getAccessor() + // IEnzymeComptroller public comptroller; // Total USDC that has passed through this contract diff --git a/eth_defi/balances.py b/eth_defi/balances.py index fb4f3a08..0b439db6 100644 --- a/eth_defi/balances.py +++ b/eth_defi/balances.py @@ -106,10 +106,10 @@ def fetch_erc20_balances_by_transfer_event( def fetch_erc20_balances_by_token_list( - web3: Web3, - owner: HexAddress, - tokens: Set[HexAddress], - block_identifier: BlockIdentifier = None, + web3: Web3, + owner: HexAddress, + tokens: Set[HexAddress], + block_identifier: BlockIdentifier = None, ) -> Dict[HexAddress, int]: """Get all current holdings of an account for a limited set of ERC-20 tokens. diff --git a/eth_defi/confirmation.py b/eth_defi/confirmation.py index 6b40617b..0cb3a178 100644 --- a/eth_defi/confirmation.py +++ b/eth_defi/confirmation.py @@ -305,20 +305,21 @@ def broadcast_and_wait_transactions_to_complete( return receipts -def _broadcast_multiple_nodes(providers: Collection[BaseProvider], signed_tx: SignedTransaction): +# Support different raw tx formats +SignedTxType = Union[SignedTransaction, SignedTransactionWithNonce] + + +def _broadcast_multiple_nodes(providers: Collection[BaseProvider], signed_tx: SignedTxType): """Attempt to broadcast a transaction through multiple provideres.""" for p in providers: - + # See SignedTransactionWithNonce nonce = getattr(signed_tx, "nonce", None) address = getattr(signed_tx, "address", None) + source = getattr(signed_tx, "source", None) name = get_provider_name(p) - logger.info( - "Broadcasting %s through %s", - signed_tx.hash, - name - ) + logger.info("Broadcasting %s through %s", signed_tx.hash.hex(), name) # Does not use any middleware web3 = Web3(p) @@ -327,27 +328,23 @@ def _broadcast_multiple_nodes(providers: Collection[BaseProvider], signed_tx: Si except ValueError as e: resp_data: dict = e.args[0] + logger.info("Broadcast JSON-RPC error %s from: %s, nonce: %s on provider: %s, got error: %s\n", signed_tx.hash.hex(), address, nonce, name, resp_data) + logger.info("Signed tx: %s", signed_tx) + logger.info("Source: %s", source) + # When we rebroadcast we are getting nonce too low errors, # both for too high and too low nonces if resp_data["message"] == "nonce too low": continue + except Exception as e: - logger.warning("Provider %s failed with tx %s from address %s, nonce %s", - name, - signed_tx.hash.hex(), - address, - nonce - ) + logger.warning("Provider %s failed with tx %s from address %s, nonce %s", name, signed_tx.hash.hex(), address, nonce) logger.exception(e) -# Support different raw tx formats -TxType = Union[SignedTransaction, SignedTransactionWithNonce] - - def wait_and_broadcast_multiple_nodes( web3: Web3, - txs: Collection[TxType], + txs: Collection[SignedTxType], confirmation_block_count: int = 0, max_timeout=datetime.timedelta(minutes=5), poll_delay=datetime.timedelta(seconds=1), @@ -446,7 +443,6 @@ def wait_and_broadcast_multiple_nodes( tx_log_level = logging.DEBUG for tx_hash in unconfirmed_txs: - try: receipt = web3.eth.get_transaction_receipt(tx_hash) except TransactionNotFound as e: diff --git a/eth_defi/hotwallet.py b/eth_defi/hotwallet.py index 1c71c527..714afe6e 100644 --- a/eth_defi/hotwallet.py +++ b/eth_defi/hotwallet.py @@ -26,26 +26,50 @@ class SignedTransactionWithNonce(NamedTuple): - """Helper class to pass around the used nonce when signing txs from the wallet. + """A better signed transaction structure. - - Emulate `SignedTransaction` from web3.py package + Helper class to pass around the used nonce when signing txs from the wallet. + + - Compatible with :py:class:`eth_accounts.datastructures.SignedTransaction`. Emulates its behavior + and should be backwards compatible. + + - Retains more information about the transaction source, + to allow us to diagnose broadcasting failures better - Add some debugging helpers """ + #: See SignedTransaction rawTransaction: HexBytes + + #: See SignedTransaction hash: HexBytes + + #: See SignedTransaction r: int + + #: See SignedTransaction s: int + + #: See SignedTransaction v: int + + #: What was the source nonce for this transaction nonce: int + + #: Whas was the source address for this trasaction address: str - #: Undecoded transaction data as a dict. + #: Unencoded transaction data as a dict. + #: + #: If broadcast fails, retain the source so we can debug the cause, + #: like the original gas parameters. #: - #: If broadcast fails, retain the source so we can debug the cause source: Optional[dict] = None + def __repr__(self): + return f"" + @property def raw_transaction(self) -> HexBytes: """Get the bytes to be broadcasted to the P2P network.""" diff --git a/eth_defi/provider/fallback.py b/eth_defi/provider/fallback.py index 87b4c77e..95bc12eb 100644 --- a/eth_defi/provider/fallback.py +++ b/eth_defi/provider/fallback.py @@ -144,12 +144,7 @@ def switch_provider(self): old_provider_name = get_provider_name(provider) self.currently_active_provider = (self.currently_active_provider + 1) % len(self.providers) new_provider_name = get_provider_name(self.get_active_provider()) - logger.log( - self.switchover_noisiness, - "Switched RPC providers %s -> %s\n", - old_provider_name, - new_provider_name - ) + logger.log(self.switchover_noisiness, "Switched RPC providers %s -> %s\n", old_provider_name, new_provider_name) def get_active_provider(self) -> NamedProvider: """Get currently active provider. @@ -191,7 +186,6 @@ def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: return resp_data except Exception as e: - if is_retryable_http_exception( e, retryable_rpc_error_codes=self.retryable_rpc_error_codes, @@ -203,18 +197,7 @@ def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: if i < self.retries: # Black messes up string new lines here # See https://github.com/psf/black/issues/1837 - logger.log( - self.switchover_noisiness, - "Encountered JSON-RPC retryable error %s when calling method:\n" - "%s(%s)\n " - "Retrying in %f seconds, retry #%d / %d", - e, - method, - params, - current_sleep, - i, - self.retries - ) + logger.log(self.switchover_noisiness, "Encountered JSON-RPC retryable error %s when calling method:\n" "%s(%s)\n " "Retrying in %f seconds, retry #%d / %d", e, method, params, current_sleep, i, self.retries) time.sleep(current_sleep) current_sleep *= self.backoff self.retry_count += 1 @@ -299,4 +282,4 @@ def get_fallback_provider(web3: Web3) -> FallbackProvider: if call_provider: return cast(FallbackProvider, call_provider) - raise AssertionError(f"Does not know how fallback provider is configured: {[provider]}") \ No newline at end of file + raise AssertionError(f"Does not know how fallback provider is configured: {[provider]}") diff --git a/pyproject.toml b/pyproject.toml index 07132724..5d144594 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "web3-ethereum-defi" -version = "0.22.22" +version = "0.22.23" description = "Python library for Uniswap, Aave, ChainLink, Enzyme and other protocols on BNB Chain, Polygon, Ethereum and other blockchains" authors = ["Mikko Ohtamaa "] license = "MIT" diff --git a/tests/rpc/test_fallback_provider.py b/tests/rpc/test_fallback_provider.py index 1833fef5..74efbda6 100644 --- a/tests/rpc/test_fallback_provider.py +++ b/tests/rpc/test_fallback_provider.py @@ -245,4 +245,4 @@ def test_broadcast_and_wait_multiple(web3: Web3, deployer: str): ) assert signed_tx2.hash in receipt_map - assert signed_tx3.hash in receipt_map \ No newline at end of file + assert signed_tx3.hash in receipt_map